0025422: Visualization, TKOpenGl - support re-assignment of new window to existing...
[occt.git] / src / OpenGl / OpenGl_GraphicDriver_7.cxx
1 // Created on: 2011-10-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 <OpenGl_GraphicDriver.hxx>
17
18 #include <OpenGl_FrameBuffer.hxx>
19
20 #include <OpenGl_Structure.hxx>
21 #include <OpenGl_CView.hxx>
22 #include <OpenGl_Text.hxx>
23
24 /*----------------------------------------------------------------------*/
25
26 void OpenGl_GraphicDriver::ActivateView (const Graphic3d_CView& ACView)
27 {
28   const OpenGl_CView *aCView = (const OpenGl_CView *)ACView.ptrView;
29   if (aCView)
30     aCView->WS->SetActiveView(aCView->View);
31 }
32
33 void OpenGl_GraphicDriver::AntiAliasing (const Graphic3d_CView& ACView, const Standard_Boolean AFlag)
34 {
35   const OpenGl_CView *aCView = (const OpenGl_CView *)ACView.ptrView;
36   if (aCView)
37     aCView->View->SetAntiAliasing(AFlag);
38 }
39
40 void OpenGl_GraphicDriver::Background (const Graphic3d_CView& ACView)
41 {
42   const OpenGl_CView *aCView = (const OpenGl_CView *)ACView.ptrView;
43   if (aCView)
44   {
45     aCView->WS->SetBackgroundColor(ACView.DefWindow.Background.r,ACView.DefWindow.Background.g,ACView.DefWindow.Background.b);
46   }
47 }
48
49 void OpenGl_GraphicDriver::GradientBackground (const Graphic3d_CView& ACView,
50                                               const Quantity_Color& AColor1,
51                                               const Quantity_Color& AColor2,
52                                               const Aspect_GradientFillMethod AType)
53 {
54   const OpenGl_CView *aCView = (const OpenGl_CView *)ACView.ptrView;
55   if (aCView)
56   {
57     aCView->View->SetBackgroundGradient(AColor1,AColor2,AType);
58   }
59 }
60
61 void OpenGl_GraphicDriver::ClipLimit (const Graphic3d_CView& ACView, const Standard_Boolean AWait)
62 {
63   const OpenGl_CView *aCView = (const OpenGl_CView *)ACView.ptrView;
64   if (aCView)
65   {
66     aCView->View->SetClipLimit(ACView);
67     if (!AWait)
68     {
69       aCView->WS->Resize(ACView.DefWindow);
70     }
71   }
72 }
73
74 void OpenGl_GraphicDriver::DeactivateView (const Graphic3d_CView& ACView)
75 {
76   const OpenGl_CView *aCView = (const OpenGl_CView *)ACView.ptrView;
77   if (aCView)
78   {
79     const Handle(OpenGl_View) aDummyView;
80     aCView->WS->SetActiveView(aDummyView);
81   }
82 }
83
84 void OpenGl_GraphicDriver::DepthCueing (const Graphic3d_CView& ACView, const Standard_Boolean AFlag)
85 {
86   const OpenGl_CView *aCView = (const OpenGl_CView *)ACView.ptrView;
87   if (aCView)
88     aCView->View->SetFog(ACView, AFlag);
89 }
90
91 void OpenGl_GraphicDriver::RatioWindow (const Graphic3d_CView& theCView)
92 {
93   const OpenGl_CView* aCView = (const OpenGl_CView* )theCView.ptrView;
94   if (aCView != NULL)
95     aCView->WS->Resize (theCView.DefWindow);
96 }
97
98 void OpenGl_GraphicDriver::Redraw (const Graphic3d_CView& ACView,
99                                    const Aspect_CLayer2d& ACUnderLayer,
100                                    const Aspect_CLayer2d& ACOverLayer,
101                                    const Standard_Integer /*x*/,
102                                    const Standard_Integer /*y*/,
103                                    const Standard_Integer /*width*/,
104                                    const Standard_Integer /*height*/)
105 {
106   if (ACView.RenderParams.Method == Graphic3d_RM_RAYTRACING
107   && !myCaps->vboDisable
108   && !myCaps->keepArrayData)
109   {
110     if (ACView.WasRedrawnGL)
111     {
112       myDeviceLostFlag = Standard_True;
113     }
114
115     myCaps->keepArrayData = Standard_True;
116   }
117
118   const OpenGl_CView *aCView = (const OpenGl_CView *)ACView.ptrView;
119   if (aCView)
120   {
121     /*if( width <= 0 || height <= 0  )
122       aCView->WS->Redraw(ACView, ACUnderLayer, ACOverLayer);
123     else
124       aCView->WS->RedrawArea(ACView, ACUnderLayer, ACOverLayer, x, y, width, height);*/
125     // Always do full redraw
126     aCView->WS->Redraw(ACView, ACUnderLayer, ACOverLayer);
127   }
128 }
129
130 void OpenGl_GraphicDriver::RedrawImmediate (const Graphic3d_CView& theCView,
131                                             const Aspect_CLayer2d& theCUnderLayer,
132                                             const Aspect_CLayer2d& theCOverLayer)
133 {
134   const OpenGl_CView* aCView = (const OpenGl_CView* )theCView.ptrView;
135   if (aCView != NULL)
136   {
137     aCView->WS->RedrawImmediate (theCView, theCUnderLayer, theCOverLayer);
138   }
139 }
140
141 void OpenGl_GraphicDriver::Invalidate (const Graphic3d_CView& theCView)
142 {
143   const OpenGl_CView* aCView = (const OpenGl_CView* )theCView.ptrView;
144   if (aCView != NULL)
145   {
146     aCView->WS->Invalidate (theCView);
147   }
148 }
149
150 Graphic3d_PtrFrameBuffer OpenGl_GraphicDriver::FBOCreate (const Graphic3d_CView& ACView, const Standard_Integer theWidth, const Standard_Integer theHeight)
151 {
152   const OpenGl_CView *aCView = (const OpenGl_CView *)ACView.ptrView;
153   if (aCView)
154     return aCView->WS->FBOCreate(theWidth, theHeight);
155   return (Graphic3d_PtrFrameBuffer)NULL;
156 }
157
158 Graphic3d_PtrFrameBuffer OpenGl_Workspace::FBOCreate (const Standard_Integer theWidth,
159                                                       const Standard_Integer theHeight)
160 {
161   // activate OpenGL context
162   if (!Activate())
163     return NULL;
164
165   // create the FBO
166   const Handle(OpenGl_Context)& aCtx = GetGlContext();
167   OpenGl_FrameBuffer* aFrameBuffer = new OpenGl_FrameBuffer();
168   if (!aFrameBuffer->Init (aCtx, theWidth, theHeight))
169   {
170     aFrameBuffer->Release (aCtx.operator->());
171     delete aFrameBuffer;
172     return NULL;
173   }
174   return (Graphic3d_PtrFrameBuffer )aFrameBuffer;
175 }
176
177 void OpenGl_GraphicDriver::FBORelease (const Graphic3d_CView& ACView, Graphic3d_PtrFrameBuffer& theFBOPtr)
178 {
179   if (theFBOPtr == NULL)
180     return;
181   const OpenGl_CView *aCView = (const OpenGl_CView *)ACView.ptrView;
182   if (aCView)
183   {
184     aCView->WS->FBORelease(theFBOPtr);
185     theFBOPtr = NULL;
186   }
187 }
188
189 void OpenGl_Workspace::FBORelease (Graphic3d_PtrFrameBuffer theFBOPtr)
190 {
191   // activate OpenGL context
192   if (!Activate()
193    || theFBOPtr == NULL)
194   {
195     return;
196   }
197
198   // release the object
199   OpenGl_FrameBuffer* aFrameBuffer = (OpenGl_FrameBuffer*)theFBOPtr;
200   if (aFrameBuffer != NULL)
201   {
202     aFrameBuffer->Release (GetGlContext().operator->());
203   }
204   delete aFrameBuffer;
205 }
206
207 void OpenGl_GraphicDriver::FBOGetDimensions (const Graphic3d_CView& ,
208                                              const Graphic3d_PtrFrameBuffer theFBOPtr,
209                                              Standard_Integer& theWidth,    Standard_Integer& theHeight,
210                                              Standard_Integer& theWidthMax, Standard_Integer& theHeightMax)
211 {
212   if (theFBOPtr == NULL)
213   {
214     return;
215   }
216   const OpenGl_FrameBuffer* aFrameBuffer = (const OpenGl_FrameBuffer* )theFBOPtr;
217   theWidth  = aFrameBuffer->GetVPSizeX(); // current viewport size
218   theHeight = aFrameBuffer->GetVPSizeY();
219   theWidthMax  = aFrameBuffer->GetSizeX(); // texture size
220   theHeightMax = aFrameBuffer->GetSizeY();
221 }
222
223 void OpenGl_GraphicDriver::FBOChangeViewport (const Graphic3d_CView& ,
224                                               Graphic3d_PtrFrameBuffer& theFBOPtr,
225                                               const Standard_Integer theWidth, const Standard_Integer theHeight)
226 {
227   if (theFBOPtr == NULL)
228   {
229     return;
230   }
231   OpenGl_FrameBuffer* aFrameBuffer = (OpenGl_FrameBuffer* )theFBOPtr;
232   aFrameBuffer->ChangeViewport (theWidth, theHeight);
233 }
234
235 inline bool getDataFormat (const Image_PixMap& theData,
236                            GLenum&             thePixelFormat,
237                            GLenum&             theDataType)
238 {
239   thePixelFormat = GL_RGB;
240   theDataType    = GL_UNSIGNED_BYTE;
241   switch (theData.Format())
242   {
243   #if !defined(GL_ES_VERSION_2_0)
244     case Image_PixMap::ImgGray:
245       thePixelFormat = GL_DEPTH_COMPONENT;
246       theDataType    = GL_UNSIGNED_BYTE;
247       return true;
248     case Image_PixMap::ImgGrayF:
249       thePixelFormat = GL_DEPTH_COMPONENT;
250       theDataType    = GL_FLOAT;
251       return true;
252     case Image_PixMap::ImgBGR:
253       thePixelFormat = GL_BGR;
254       theDataType    = GL_UNSIGNED_BYTE;
255       return true;
256     case Image_PixMap::ImgBGRA:
257     case Image_PixMap::ImgBGR32:
258       thePixelFormat = GL_BGRA;
259       theDataType    = GL_UNSIGNED_BYTE;
260       return true;
261     case Image_PixMap::ImgBGRF:
262       thePixelFormat = GL_BGR;
263       theDataType    = GL_FLOAT;
264       return true;
265     case Image_PixMap::ImgBGRAF:
266       thePixelFormat = GL_BGRA;
267       theDataType    = GL_FLOAT;
268       return true;
269   #endif
270     case Image_PixMap::ImgRGB:
271       thePixelFormat = GL_RGB;
272       theDataType    = GL_UNSIGNED_BYTE;
273       return true;
274     case Image_PixMap::ImgRGBA:
275     case Image_PixMap::ImgRGB32:
276       thePixelFormat = GL_RGBA;
277       theDataType    = GL_UNSIGNED_BYTE;
278       return true;
279     case Image_PixMap::ImgRGBF:
280       thePixelFormat = GL_RGB;
281       theDataType    = GL_FLOAT;
282       return true;
283     case Image_PixMap::ImgRGBAF:
284       thePixelFormat = GL_RGBA;
285       theDataType    = GL_FLOAT;
286       return true;
287     default:
288       return false;
289   }
290 }
291
292 Standard_Boolean OpenGl_GraphicDriver::BufferDump (const Graphic3d_CView&      theCView,
293                                                    Image_PixMap&               theImage,
294                                                    const Graphic3d_BufferType& theBufferType)
295 {
296   const OpenGl_CView* aCView = (const OpenGl_CView* )theCView.ptrView;
297   return (aCView != NULL) && aCView->WS->BufferDump ((OpenGl_FrameBuffer* )theCView.ptrFBO, theImage, theBufferType);
298 }
299
300 Standard_Boolean OpenGl_Workspace::BufferDump (OpenGl_FrameBuffer*         theFBOPtr,
301                                                Image_PixMap&               theImage,
302                                                const Graphic3d_BufferType& theBufferType)
303 {
304   GLenum aFormat, aType;
305   if (theImage.IsEmpty()
306    || !getDataFormat (theImage, aFormat, aType)
307    || !Activate())
308   {
309     return Standard_False;
310   }
311 #if !defined(GL_ES_VERSION_2_0)
312   GLint aReadBufferPrev = GL_BACK;
313   if (theBufferType == Graphic3d_BT_Depth
314    && aFormat != GL_DEPTH_COMPONENT)
315   {
316     return Standard_False;
317   }
318 #endif
319
320   // bind FBO if used
321   if (theFBOPtr != NULL && theFBOPtr->IsValid())
322   {
323     theFBOPtr->BindBuffer (GetGlContext());
324   }
325   else
326   {
327   #if !defined(GL_ES_VERSION_2_0)
328     glGetIntegerv (GL_READ_BUFFER, &aReadBufferPrev);
329     GLint aDrawBufferPrev = GL_BACK;
330     glGetIntegerv (GL_DRAW_BUFFER, &aDrawBufferPrev);
331     glReadBuffer (aDrawBufferPrev);
332   #endif
333   }
334
335   // setup alignment
336   const GLint anAligment   = Min (GLint(theImage.MaxRowAligmentBytes()), 8); // limit to 8 bytes for OpenGL
337   glPixelStorei (GL_PACK_ALIGNMENT, anAligment);
338
339 #if !defined(GL_ES_VERSION_2_0)
340   const GLint anExtraBytes = (GLint )theImage.RowExtraBytes();
341   const GLint aPixelsWidth = GLint(theImage.SizeRowBytes() / theImage.SizePixelBytes());
342   glPixelStorei (GL_PACK_ROW_LENGTH, (anExtraBytes >= anAligment) ? aPixelsWidth : 0);
343 #endif
344
345   if (theImage.IsTopDown())
346   {
347     // copy row by row
348     for (Standard_Size aRow = 0; aRow < theImage.SizeY(); ++aRow)
349     {
350       // Image_PixMap rows indexation always starts from the upper corner
351       // while order in memory depends on the flag and processed by ChangeRow() method
352       glReadPixels (0, GLint(theImage.SizeY() - aRow - 1), GLsizei (theImage.SizeX()), 1, aFormat, aType, theImage.ChangeRow (aRow));
353     }
354   }
355   else
356   {
357     glReadPixels (0, 0, GLsizei (theImage.SizeX()), GLsizei (theImage.SizeY()), aFormat, aType, theImage.ChangeData());
358   }
359
360   glPixelStorei (GL_PACK_ALIGNMENT,  1);
361 #if !defined(GL_ES_VERSION_2_0)
362   glPixelStorei (GL_PACK_ROW_LENGTH, 0);
363 #endif
364
365   if (theFBOPtr != NULL && theFBOPtr->IsValid())
366   {
367     theFBOPtr->UnbindBuffer (GetGlContext());
368   }
369   else
370   {
371   #if !defined(GL_ES_VERSION_2_0)
372     glReadBuffer (aReadBufferPrev);
373   #endif
374   }
375   return Standard_True;
376 }
377
378 void OpenGl_GraphicDriver::RemoveView (const Graphic3d_CView& theCView)
379 {
380   Handle(OpenGl_Context)   aCtx = GetSharedContext();
381   Handle(OpenGl_View)      aView;
382   Handle(OpenGl_Workspace) aWindow;
383   if (myMapOfWS.Find (theCView.WsId, aWindow))
384   {
385     myMapOfWS.UnBind (theCView.WsId);
386   }
387   if (!aWindow.IsNull())
388   {
389     if (aWindow->GetGlContext()->MakeCurrent())
390     {
391       aCtx = aWindow->GetGlContext();
392     }
393     else
394     {
395       // try to hijack another context if any
396       const Handle(OpenGl_Context)& anOtherCtx = GetSharedContext();
397       if (!anOtherCtx.IsNull()
398        && anOtherCtx != aWindow->GetGlContext())
399       {
400         aCtx = anOtherCtx;
401         aCtx->MakeCurrent();
402       }
403     }
404   }
405   if (myMapOfView.Find (theCView.ViewId, aView))
406   {
407     aView->ReleaseGlResources (aCtx);
408     myMapOfView.UnBind (theCView.ViewId);
409   }
410
411   if (myMapOfWS.IsEmpty())
412   {
413     // The last view removed but some objects still present.
414     // Release GL resources now without object destruction.
415     for (NCollection_DataMap<Standard_Integer, OpenGl_Structure*>::Iterator aStructIt (myMapOfStructure);
416          aStructIt.More (); aStructIt.Next())
417     {
418       OpenGl_Structure* aStruct = aStructIt.ChangeValue();
419       aStruct->ReleaseGlResources (aCtx);
420     }
421     myTempText->Release (aCtx.operator->());
422     myDeviceLostFlag = !myMapOfStructure.IsEmpty();
423   }
424
425   OpenGl_CView* aCView = (OpenGl_CView* )theCView.ptrView;
426   delete aCView;
427   ((Graphic3d_CView *)&theCView)->ptrView = NULL;
428
429   aCtx.Nullify();
430   aView.Nullify();
431   aWindow.Nullify();
432 }
433
434 void OpenGl_GraphicDriver::SetLight (const Graphic3d_CView& ACView)
435 {
436   const OpenGl_CView *aCView = (const OpenGl_CView *)ACView.ptrView;
437   if (aCView)
438     aCView->View->SetLights(ACView.Context);
439 }
440
441 void OpenGl_GraphicDriver::SetClipPlanes (const Graphic3d_CView& theCView)
442 {
443   const OpenGl_CView *aCView = (const OpenGl_CView *)theCView.ptrView;
444   if (aCView)
445   {
446     aCView->View->SetClipPlanes (theCView.Context.ClipPlanes);
447   }
448 }
449
450 //=======================================================================
451 //function : SetCamera
452 //purpose  :
453 //=======================================================================
454 void OpenGl_GraphicDriver::SetCamera (const Graphic3d_CView& theCView)
455 {
456   const OpenGl_CView *aCView = (const OpenGl_CView *)theCView.ptrView;
457   if (aCView)
458   {
459     aCView->View->SetCamera (theCView.Context.Camera);
460   }
461 }
462
463 void OpenGl_GraphicDriver::SetVisualisation (const Graphic3d_CView& ACView)
464 {
465   const OpenGl_CView *aCView = (const OpenGl_CView *)ACView.ptrView;
466   if (aCView)
467   {
468     aCView->View->SetVisualisation(ACView.Context);
469     aCView->WS->UseZBuffer() = ( ACView.Context.Visualization == 0? (ACView.Context.ZBufferActivity == 1) : (ACView.Context.ZBufferActivity != 0) );
470   }
471 }
472
473 void OpenGl_GraphicDriver::Transparency (const Graphic3d_CView& ACView, const Standard_Boolean AFlag)
474 {
475   const OpenGl_CView *aCView = (const OpenGl_CView *)ACView.ptrView;
476   if (aCView)
477     aCView->WS->UseTransparency(AFlag);
478 }
479
480 // =======================================================================
481 // function : InvalidateBVHData
482 // purpose  :
483 // =======================================================================
484 void OpenGl_GraphicDriver::InvalidateBVHData (Graphic3d_CView& theCView, const Standard_Integer theLayerId)
485 {
486   OpenGl_CView *aCView = (OpenGl_CView *)theCView.ptrView;
487   if(aCView)
488   {
489     aCView->View->InvalidateBVHData (theLayerId);
490   }
491 }
492
493 Standard_Boolean OpenGl_GraphicDriver::View (Graphic3d_CView& theCView)
494 {
495   Handle(OpenGl_Context) aShareCtx = GetSharedContext();
496   if (myMapOfView.IsBound (theCView.ViewId))
497   {
498     OpenGl_CView* aCView = (OpenGl_CView* )theCView.ptrView;
499     if (!myMapOfWS.IsBound (theCView.WsId)
500      || aCView == NULL)
501     {
502       return Standard_False;
503     }
504
505     Handle(OpenGl_Workspace) aWS = new OpenGl_Workspace (this, theCView.DefWindow, theCView.GContext, myCaps, aShareCtx);
506     aCView->WS = aWS;
507     aWS->SetActiveView (aCView->View);
508
509     myMapOfWS.UnBind (theCView.WsId);
510     myMapOfWS.Bind   (theCView.WsId, aWS);
511     return Standard_True;
512   }
513
514   Handle(OpenGl_Workspace) aWS       = new OpenGl_Workspace (this, theCView.DefWindow, theCView.GContext, myCaps, aShareCtx);
515   Handle(OpenGl_View)      aView     = new OpenGl_View (theCView.Context, &myStateCounter);
516   myMapOfWS  .Bind (theCView.WsId,   aWS);
517   myMapOfView.Bind (theCView.ViewId, aView);
518
519   OpenGl_CView* aCView = new OpenGl_CView();
520   aCView->View = aView;
521   aCView->WS   = aWS;
522   theCView.ptrView = aCView;
523   aWS->SetActiveView (aCView->View);
524
525   return Standard_True;
526 }
527
528 void OpenGl_GraphicDriver::SetBackFacingModel (const Graphic3d_CView& ACView)
529 {
530   const OpenGl_CView *aCView = (const OpenGl_CView *)ACView.ptrView;
531   if (aCView)
532     aCView->View->SetBackfacing(ACView.Backfacing);
533 }
534
535 //=======================================================================
536 //function : AddZLayer
537 //purpose  :
538 //=======================================================================
539
540 void OpenGl_GraphicDriver::AddZLayer (const Graphic3d_CView& theCView,
541                                       const Standard_Integer theLayerId)
542 {
543   const OpenGl_CView *aCView = (const OpenGl_CView *)theCView.ptrView;
544   if (aCView)
545     aCView->View->AddZLayer (theLayerId);
546 }
547
548 //=======================================================================
549 //function : RemoveZLayer
550 //purpose  :
551 //=======================================================================
552 void OpenGl_GraphicDriver::RemoveZLayer (const Graphic3d_CView& theCView,
553                                          const Standard_Integer theLayerId)
554 {
555   const OpenGl_CView* aCView = (const OpenGl_CView *)theCView.ptrView;
556   if (aCView)
557     aCView->View->RemoveZLayer (theLayerId);
558 }
559
560 //=======================================================================
561 //function : SetZLayerSettings
562 //purpose  :
563 //=======================================================================
564 Standard_EXPORT void OpenGl_GraphicDriver::SetZLayerSettings (const Graphic3d_CView& theCView,
565                                                               const Standard_Integer theLayerId,
566                                                               const Graphic3d_ZLayerSettings& theSettings)
567 {
568   const OpenGl_CView* aCView = (const OpenGl_CView* )theCView.ptrView;
569   if (aCView)
570     aCView->View->SetZLayerSettings (theLayerId, theSettings);
571 }