0023428: Extend OpenGl_Context to use Geometry Shaders extension
[occt.git] / src / OpenGl / OpenGl_Window.cxx
1 // Created on: 2011-09-20
2 // Created by: Sergey ZERCHANINOV
3 // Copyright (c) 2011-2012 OPEN CASCADE SAS
4 //
5 // The content of this file is subject to the Open CASCADE Technology Public
6 // License Version 6.5 (the "License"). You may not use the content of this file
7 // except in compliance with the License. Please obtain a copy of the License
8 // at http://www.opencascade.org and read it completely before using this file.
9 //
10 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
11 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
12 //
13 // The Original Code and all software distributed under the License is
14 // distributed on an "AS IS" basis, without warranty of any kind, and the
15 // Initial Developer hereby disclaims all such warranties, including without
16 // limitation, any warranties of merchantability, fitness for a particular
17 // purpose or non-infringement. Please see the License for the specific terms
18 // and conditions governing the rights and limitations under the License.
19
20
21 #include <InterfaceGraphic.hxx>
22
23 #include <OpenGl_Window.hxx>
24
25 #include <OpenGl_Context.hxx>
26 #include <OpenGl_Display.hxx>
27
28 #include <Aspect_GraphicDeviceDefinitionError.hxx>
29 #include <TCollection_AsciiString.hxx>
30
31 #include <GL/glu.h> // gluOrtho2D()
32
33 IMPLEMENT_STANDARD_HANDLE(OpenGl_Window,MMgt_TShared)
34 IMPLEMENT_STANDARD_RTTIEXT(OpenGl_Window,MMgt_TShared)
35
36 namespace
37 {
38   static const TEL_COLOUR THE_DEFAULT_BG_COLOR = { { 0.F, 0.F, 0.F, 1.F } };
39
40 #if (defined(_WIN32) || defined(__WIN32__))
41   static int find_pixel_format (HDC hDC, PIXELFORMATDESCRIPTOR* pfd, const Standard_Boolean dbuff)
42   {
43     PIXELFORMATDESCRIPTOR pfd0;
44     memset (&pfd0, 0, sizeof (PIXELFORMATDESCRIPTOR));
45     pfd0.nSize           = sizeof (PIXELFORMATDESCRIPTOR);
46     pfd0.nVersion        = 1;
47     pfd0.dwFlags         = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | (dbuff ? PFD_DOUBLEBUFFER : PFD_SUPPORT_GDI);
48     pfd0.iPixelType      = PFD_TYPE_RGBA;
49     pfd0.iLayerType      = PFD_MAIN_PLANE;
50
51     int       iPixelFormat = 0;
52     int       iGood = 0;
53     const int cBits[] = { 32, 24 };
54     const int dBits[] = { 32, 24, 16 };
55
56     int i, j;
57     for (i = 0; i < sizeof(dBits) / sizeof(int); i++)
58     {
59       pfd0.cDepthBits = dBits[i];
60       iGood = 0;
61       for (j = 0; j < sizeof(cBits) / sizeof(int); j++)
62       {
63         pfd0.cColorBits = cBits[j];
64         iPixelFormat = ChoosePixelFormat (hDC, &pfd0);
65         if (iPixelFormat)
66         {
67           pfd->cDepthBits = 0;
68           pfd->cColorBits = 0;
69           DescribePixelFormat (hDC, iPixelFormat, sizeof (PIXELFORMATDESCRIPTOR), pfd);
70           if (pfd->cColorBits >= cBits[j] && pfd->cDepthBits >= dBits[i])
71             break;
72           if (iGood == 0)
73             iGood = iPixelFormat;
74         }
75       }
76       if (j < sizeof(cBits) / sizeof(int))
77         break;
78     }
79
80     if (iPixelFormat == 0)
81       iPixelFormat = iGood;
82
83     return iPixelFormat;
84   }
85 #else
86   static Bool WaitForNotify (Display* theDisp, XEvent* theEv, char* theArg)
87   {
88     return (theEv->type == MapNotify) && (theEv->xmap.window == (Window )theArg);
89   }
90 #endif
91
92 };
93
94 // =======================================================================
95 // function : OpenGl_Window
96 // purpose  :
97 // =======================================================================
98 OpenGl_Window::OpenGl_Window (const Handle(OpenGl_Display)& theDisplay,
99                               const CALL_DEF_WINDOW&        theCWindow,
100                               Aspect_RenderingContext       theGContext,
101                               const Handle(OpenGl_Context)& theShareCtx)
102 : myDisplay (theDisplay),
103   myGlContext (new OpenGl_Context()),
104   myOwnGContext (theGContext == 0),
105 #if (defined(_WIN32) || defined(__WIN32__))
106   mySysPalInUse (FALSE),
107 #endif
108   myWidth ((Standard_Integer )theCWindow.dx),
109   myHeight ((Standard_Integer )theCWindow.dy),
110   myBgColor (THE_DEFAULT_BG_COLOR),
111   myDither (theDisplay->Dither()),
112   myBackDither (theDisplay->BackDither())
113 {
114   myBgColor.rgb[0] = theCWindow.Background.r;
115   myBgColor.rgb[1] = theCWindow.Background.g;
116   myBgColor.rgb[2] = theCWindow.Background.b;
117
118 #if (defined(_WIN32) || defined(__WIN32__))
119   HWND  aWindow   = (HWND )theCWindow.XWindow;
120   HDC   aWindowDC = GetDC (aWindow);
121   HGLRC aGContext = (HGLRC )theGContext;
122
123   PIXELFORMATDESCRIPTOR pfd;
124   int iPixelFormat = find_pixel_format (aWindowDC, &pfd, myDisplay->DBuffer());
125   if (iPixelFormat == 0)
126   {
127     ReleaseDC (aWindow, aWindowDC);
128
129     TCollection_AsciiString aMsg ("OpenGl_Window::CreateWindow: ChoosePixelFormat failed. Error code: ");
130     aMsg += (int )GetLastError();
131     Aspect_GraphicDeviceDefinitionError::Raise (aMsg.ToCString());
132     return;
133   }
134
135   if (pfd.dwFlags & PFD_NEED_PALETTE)
136   {
137     WINDOW_DATA* wd = (WINDOW_DATA* )GetWindowLongPtr (aWindow, GWLP_USERDATA);
138
139     mySysPalInUse = (pfd.dwFlags & PFD_NEED_SYSTEM_PALETTE) ? TRUE : FALSE;
140     InterfaceGraphic_RealizePalette (aWindowDC, wd->hPal, FALSE, mySysPalInUse);
141   }
142
143   if (myDither)
144     myDither = (pfd.cColorBits <= 8);
145
146   if (myBackDither)
147     myBackDither = (pfd.cColorBits <= 8);
148
149   if (!SetPixelFormat (aWindowDC, iPixelFormat, &pfd))
150   {
151     ReleaseDC (aWindow, aWindowDC);
152
153     TCollection_AsciiString aMsg("OpenGl_Window::CreateWindow: SetPixelFormat failed. Error code: ");
154     aMsg += (int )GetLastError();
155     Aspect_GraphicDeviceDefinitionError::Raise (aMsg.ToCString());
156     return;
157   }
158
159   if (aGContext == NULL)
160   {
161     aGContext = wglCreateContext (aWindowDC);
162     if (aGContext == NULL)
163     {
164       ReleaseDC (aWindow, aWindowDC);
165
166       TCollection_AsciiString aMsg ("OpenGl_Window::CreateWindow: wglCreateContext failed. Error code: ");
167       aMsg += (int )GetLastError();
168       Aspect_GraphicDeviceDefinitionError::Raise (aMsg.ToCString());
169       return;
170     }
171   }
172
173   // all GL context within one OpenGl_GraphicDriver should be shared!
174   if (!theShareCtx.IsNull() && wglShareLists ((HGLRC )theShareCtx->myGContext, aGContext) != TRUE)
175   {
176     TCollection_AsciiString aMsg ("OpenGl_Window::CreateWindow: wglShareLists failed. Error code: ");
177     aMsg += (int )GetLastError();
178     Aspect_GraphicDeviceDefinitionError::Raise (aMsg.ToCString());
179     return;
180   }
181
182   myGlContext->Init ((Aspect_Handle )aWindow, (Aspect_Handle )aWindowDC, (Aspect_RenderingContext )aGContext);
183 #else
184   WINDOW aParent = (WINDOW )theCWindow.XWindow;
185   WINDOW aWindow = 0;
186   DISPLAY* aDisp = (DISPLAY* )myDisplay->GetDisplay();
187   GLXContext aGContext = (GLXContext )theGContext;
188
189   XWindowAttributes wattr;
190   XGetWindowAttributes (aDisp, aParent, &wattr);
191   const int scr = DefaultScreen (aDisp);
192
193   XVisualInfo* aVis = NULL;
194   {
195     unsigned long aVisInfoMask = VisualIDMask | VisualScreenMask;
196     XVisualInfo aVisInfo;
197     aVisInfo.visualid = wattr.visual->visualid;
198     aVisInfo.screen   = scr;
199     int aNbItems;
200     aVis = XGetVisualInfo (aDisp, aVisInfoMask, &aVisInfo, &aNbItems);
201   }
202
203   if (!myOwnGContext)
204   {
205     if (aVis != NULL)
206     {
207       Aspect_GraphicDeviceDefinitionError::Raise ("OpenGl_Window::CreateWindow: XGetVisualInfo failed.");
208       return;
209     }
210
211     aWindow = aParent;
212   }
213   else
214   {
215   #if defined(__linux) || defined(Linux) || defined(__APPLE__)
216     if (aVis != NULL)
217     {
218       // check Visual for OpenGl context's parameters compability
219       int isGl = 0, isDoubleBuffer = 0, isRGBA = 0, aDepthSize = 0;
220
221       if (glXGetConfig (aDisp, aVis, GLX_USE_GL, &isGl) != 0)
222         isGl = 0;
223
224       if (glXGetConfig (aDisp, aVis, GLX_RGBA, &isRGBA) != 0)
225         isRGBA = 0;
226
227       if (glXGetConfig (aDisp, aVis, GLX_DOUBLEBUFFER, &isDoubleBuffer) != 0)
228         isDoubleBuffer = 0;
229
230       if (glXGetConfig (aDisp, aVis, GLX_DEPTH_SIZE, &aDepthSize) != 0)
231         aDepthSize = 0;
232
233       if (!isGl || !aDepthSize || !isRGBA  || (isDoubleBuffer ? 1 : 0) != (myDisplay->DBuffer()? 1 : 0))
234       {
235         XFree (aVis);
236         aVis = NULL;
237       }
238     }
239   #endif
240
241     if (aVis == NULL)
242     {
243       int anIter = 0;
244       int anAttribs[11];
245       anAttribs[anIter++] = GLX_RGBA;
246
247       anAttribs[anIter++] = GLX_DEPTH_SIZE;
248       anAttribs[anIter++] = 1;
249
250       anAttribs[anIter++] = GLX_RED_SIZE;
251       anAttribs[anIter++] = (wattr.depth <= 8) ? 0 : 1;
252
253       anAttribs[anIter++] = GLX_GREEN_SIZE;
254       anAttribs[anIter++] = (wattr.depth <= 8) ? 0 : 1;
255
256       anAttribs[anIter++] = GLX_BLUE_SIZE;
257       anAttribs[anIter++] = (wattr.depth <= 8) ? 0 : 1;
258
259       if (myDisplay->DBuffer())
260         anAttribs[anIter++] = GLX_DOUBLEBUFFER;
261
262       anAttribs[anIter++] = None;
263
264       aVis = glXChooseVisual (aDisp, scr, anAttribs);
265       if (aVis == NULL)
266       {
267         Aspect_GraphicDeviceDefinitionError::Raise ("OpenGl_Window::CreateWindow: glXChooseVisual failed.");
268         return;
269       }
270     }
271
272     if (!theShareCtx.IsNull())
273     {
274       // ctx est une copie du previous
275       aGContext = glXCreateContext (aDisp, aVis, (GLXContext )theShareCtx->myGContext, GL_TRUE);
276     }
277     else
278     {
279       aGContext = glXCreateContext (aDisp, aVis, NULL, GL_TRUE);
280     }
281
282     if (!aGContext)
283     {
284       Aspect_GraphicDeviceDefinitionError::Raise ("OpenGl_Window::CreateWindow: glXCreateContext failed.");
285       return;
286     }
287
288     Colormap cmap = XCreateColormap (aDisp, aParent, aVis->visual, AllocNone);
289
290     XColor color;
291     color.red   = (unsigned short) (myBgColor.rgb[0] * 0xFFFF);
292     color.green = (unsigned short) (myBgColor.rgb[1] * 0xFFFF);
293     color.blue  = (unsigned short) (myBgColor.rgb[2] * 0xFFFF);
294     color.flags = DoRed | DoGreen | DoBlue;
295     XAllocColor (aDisp, cmap, &color);
296
297     XSetWindowAttributes cwa;
298     cwa.colormap         = cmap;
299     cwa.event_mask       = StructureNotifyMask;
300     cwa.border_pixel     = color.pixel;
301     cwa.background_pixel = color.pixel;
302
303     if (aVis->visualid == wattr.visual->visualid)
304     {
305       aWindow = aParent;
306     }
307     else
308     {
309       unsigned long mask = CWBackPixel | CWColormap | CWBorderPixel | CWEventMask;
310       aWindow = XCreateWindow (aDisp, aParent, 0, 0, myWidth, myHeight, 0/*bw*/, aVis->depth, InputOutput, aVis->visual, mask, &cwa);
311     }
312
313     XSetWindowBackground (aDisp, aWindow, cwa.background_pixel);
314     XClearWindow (aDisp, aWindow);
315
316     if (aWindow != aParent)
317     {
318       XEvent anEvent;
319       XMapWindow (aDisp, aWindow);
320       XIfEvent (aDisp, &anEvent, WaitForNotify, (char* )aWindow);
321     }
322   }
323
324   /*
325   * Le BackDitherProp est utilise pour le clear du background
326   * Pour eviter une difference de couleurs avec la couleur choisie
327   * par l'application (XWindow) il faut desactiver le dithering
328   * au dessus de 8 plans.
329   *
330   * Pour le DitherProp:
331   * On cherchera a activer le Dithering que si le Visual a au moins
332   * 8 plans pour le GLX_RED_SIZE. Le test est plus sur car on peut
333   * avoir une profondeur superieure a 12 mais avoir besoin du dithering.
334   * (Carte Impact avec GLX_RED_SIZE a 5 par exemple)
335   */
336
337   int aValue;
338   glXGetConfig (aDisp, aVis, GLX_RED_SIZE, &aValue);
339
340   if (myDither)
341     myDither = (aValue < 8);
342
343   if (myBackDither)
344     myBackDither = (aVis->depth <= 8);
345
346   XFree ((char* )aVis);
347
348   myGlContext->Init ((Aspect_Drawable )aWindow, (Aspect_Display )myDisplay->GetDisplay(), (Aspect_RenderingContext )aGContext);
349 #endif
350   myGlContext->Share (theShareCtx);
351
352   Init();
353 }
354
355 // =======================================================================
356 // function : ~OpenGl_Window
357 // purpose  :
358 // =======================================================================
359 OpenGl_Window::~OpenGl_Window()
360 {
361 #if (defined(_WIN32) || defined(__WIN32__))
362   HWND  aWindow   = (HWND  )myGlContext->myWindow;
363   HDC   aWindowDC = (HDC   )myGlContext->myWindowDC;
364   HGLRC aGContext = (HGLRC )myGlContext->myGContext;
365   myGlContext.Nullify();
366
367   if (myOwnGContext)
368   {
369     if (wglGetCurrentContext() != NULL)
370     {
371       wglDeleteContext (aGContext);
372     }
373     ReleaseDC (aWindow, aWindowDC);
374   }
375 #else
376   GLXDrawable aWindow   = (GLXDrawable )myGlContext->myWindow;
377   Display*    aDisplay  = (Display*    )myGlContext->myDisplay;
378   GLXContext  aGContext = (GLXContext  )myGlContext->myGContext;
379   myGlContext.Nullify();
380
381   if (aDisplay != NULL && myOwnGContext)
382   {
383     // FSXXX sync necessary if non-direct rendering
384     glXWaitGL();
385     glXDestroyContext (aDisplay, aGContext);
386   }
387 #endif
388 }
389
390 // =======================================================================
391 // function : Activate
392 // purpose  :
393 // =======================================================================
394 Standard_Boolean OpenGl_Window::Activate()
395 {
396   return myGlContext->MakeCurrent();
397 }
398
399 // =======================================================================
400 // function : Resize
401 // purpose  : call_subr_resize
402 // =======================================================================
403 void OpenGl_Window::Resize (const CALL_DEF_WINDOW& theCWindow)
404 {
405   DISPLAY* aDisp = (DISPLAY* )myDisplay->GetDisplay();
406   if (aDisp == NULL)
407     return;
408
409   // If the size is not changed - do nothing
410   if ((myWidth == theCWindow.dx) && (myHeight == theCWindow.dy))
411     return;
412
413   myWidth  = (Standard_Integer )theCWindow.dx;
414   myHeight = (Standard_Integer )theCWindow.dy;
415
416 #if (!defined(_WIN32) && !defined(__WIN32__))
417   XResizeWindow (aDisp, myGlContext->myWindow, (unsigned int )myWidth, (unsigned int )myHeight);
418   XSync (aDisp, False);
419 #endif
420
421   Init();
422 }
423
424 // =======================================================================
425 // function : ReadDepths
426 // purpose  : TelReadDepths
427 // =======================================================================
428 void OpenGl_Window::ReadDepths (const Standard_Integer theX,     const Standard_Integer theY,
429                                 const Standard_Integer theWidth, const Standard_Integer theHeight,
430                                 float* theDepths)
431 {
432   if (theDepths == NULL || !Activate())
433     return;
434
435   glMatrixMode (GL_PROJECTION);
436   glLoadIdentity();
437   gluOrtho2D (0.0, (GLdouble )myWidth, 0.0, (GLdouble )myHeight);
438   glMatrixMode (GL_MODELVIEW);
439   glLoadIdentity();
440
441   glRasterPos2i (theX, theY);
442   DisableFeatures();
443   glReadPixels (theX, theY, theWidth, theHeight, GL_DEPTH_COMPONENT, GL_FLOAT, theDepths);
444   EnableFeatures();
445 }
446
447 // =======================================================================
448 // function : SetBackgroundColor
449 // purpose  : call_subr_set_background
450 // =======================================================================
451 void OpenGl_Window::SetBackgroundColor (const Standard_ShortReal theR,
452                                         const Standard_ShortReal theG,
453                                         const Standard_ShortReal theB)
454 {
455   myBgColor.rgb[0] = theR;
456   myBgColor.rgb[1] = theG;
457   myBgColor.rgb[2] = theB;
458 }
459
460 // =======================================================================
461 // function : Init
462 // purpose  :
463 // =======================================================================
464 void OpenGl_Window::Init()
465 {
466   if (!Activate())
467     return;
468
469 #if (defined(_WIN32) || defined(__WIN32__))
470   RECT cr;
471   GetClientRect ((HWND )myGlContext->myWindow, &cr);
472   myWidth  = cr.right - cr.left;
473   myHeight = cr.bottom - cr.top;
474 #else
475   Window aRootWin;
476   int aDummy;
477   unsigned int aDummyU;
478   unsigned int aNewWidth  = 0;
479   unsigned int aNewHeight = 0;
480   DISPLAY* aDisp = (DISPLAY* )myDisplay->GetDisplay();
481   XGetGeometry (aDisp, myGlContext->myWindow, &aRootWin, &aDummy, &aDummy, &aNewWidth, &aNewHeight, &aDummyU, &aDummyU);
482   myWidth  = aNewWidth;
483   myHeight = aNewHeight;
484 #endif
485
486   glMatrixMode (GL_MODELVIEW);
487   glViewport (0, 0, myWidth, myHeight);
488
489   glDisable (GL_SCISSOR_TEST);
490   glDrawBuffer (GL_BACK);
491 }
492
493 // =======================================================================
494 // function : EnablePolygonOffset
495 // purpose  : call_subr_enable_polygon_offset
496 // =======================================================================
497 void OpenGl_Window::EnablePolygonOffset() const
498 {
499   Standard_ShortReal aFactor, aUnits;
500   myDisplay->PolygonOffset (aFactor, aUnits);
501   glPolygonOffset (aFactor, aUnits);
502   glEnable (GL_POLYGON_OFFSET_FILL);
503 }
504
505 // =======================================================================
506 // function : DisablePolygonOffset
507 // purpose  : call_subr_disable_polygon_offset
508 // =======================================================================
509 void OpenGl_Window::DisablePolygonOffset() const
510 {
511   glDisable (GL_POLYGON_OFFSET_FILL);
512 }
513
514 // =======================================================================
515 // function : EnableFeatures
516 // purpose  :
517 // =======================================================================
518 void OpenGl_Window::EnableFeatures() const
519 {
520   /*glPixelTransferi (GL_MAP_COLOR, GL_TRUE);*/
521
522   if (myDither)
523     glEnable (GL_DITHER);
524   else
525     glDisable (GL_DITHER);
526 }
527
528 // =======================================================================
529 // function : DisableFeatures
530 // purpose  :
531 // =======================================================================
532 void OpenGl_Window::DisableFeatures() const
533 {
534   glDisable (GL_DITHER);
535   glPixelTransferi (GL_MAP_COLOR, GL_FALSE);
536
537   /*
538   * Disable stuff that's likely to slow down glDrawPixels.
539   * (Omit as much of this as possible, when you know in advance
540   * that the OpenGL state will already be set correctly.)
541   */
542   glDisable(GL_ALPHA_TEST);
543   glDisable(GL_BLEND);
544   glDisable(GL_DEPTH_TEST);
545   glDisable(GL_FOG);
546   glDisable(GL_LIGHTING);
547
548   glDisable(GL_LOGIC_OP);
549   glDisable(GL_STENCIL_TEST);
550   glDisable(GL_TEXTURE_1D);
551   glDisable(GL_TEXTURE_2D);
552   glPixelTransferi(GL_MAP_COLOR, GL_FALSE);
553   glPixelTransferi(GL_RED_SCALE, 1);
554   glPixelTransferi(GL_RED_BIAS, 0);
555   glPixelTransferi(GL_GREEN_SCALE, 1);
556   glPixelTransferi(GL_GREEN_BIAS, 0);
557   glPixelTransferi(GL_BLUE_SCALE, 1);
558   glPixelTransferi(GL_BLUE_BIAS, 0);
559   glPixelTransferi(GL_ALPHA_SCALE, 1);
560   glPixelTransferi(GL_ALPHA_BIAS, 0);
561
562   /*
563   * Disable extensions that could slow down glDrawPixels.
564   * (Actually, you should check for the presence of the proper
565   * extension before making these calls.  I've omitted that
566   * code for simplicity.)
567   */
568
569 #ifdef GL_EXT_convolution
570   glDisable(GL_CONVOLUTION_1D_EXT);
571   glDisable(GL_CONVOLUTION_2D_EXT);
572   glDisable(GL_SEPARABLE_2D_EXT);
573 #endif
574
575 #ifdef GL_EXT_histogram
576   glDisable(GL_HISTOGRAM_EXT);
577   glDisable(GL_MINMAX_EXT);
578 #endif
579
580 #ifdef GL_EXT_texture3D
581   glDisable(GL_TEXTURE_3D_EXT);
582 #endif
583 }
584
585 // =======================================================================
586 // function : MakeFrontBufCurrent
587 // purpose  : TelMakeFrontBufCurrent
588 // =======================================================================
589 void OpenGl_Window::MakeFrontBufCurrent() const
590 {
591   glDrawBuffer (GL_FRONT);
592 }
593
594 // =======================================================================
595 // function : MakeBackBufCurrent
596 // purpose  : TelMakeBackBufCurrent
597 // =======================================================================
598 void OpenGl_Window::MakeBackBufCurrent() const
599 {
600   glDrawBuffer (GL_BACK);
601 }
602
603 // =======================================================================
604 // function : MakeFrontAndBackBufCurrent
605 // purpose  : TelMakeFrontAndBackBufCurrent
606 // =======================================================================
607 void OpenGl_Window::MakeFrontAndBackBufCurrent() const
608 {
609   glDrawBuffer (GL_FRONT_AND_BACK);
610 }
611
612 // =======================================================================
613 // function : GetGContext
614 // purpose  :
615 // =======================================================================
616 GLCONTEXT OpenGl_Window::GetGContext() const
617 {
618   return (GLCONTEXT )myGlContext->myGContext;
619 }