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