Salome HOME
1ec3731f6b5ee039dfcf2892ac40a2a842ff6686
[modules/shaper.git] / src / XGUI / XGUI_ViewPort.cpp
1 #ifndef WIN32
2 # ifndef GLX_GLXEXT_LEGACY
3 #  define GLX_GLXEXT_LEGACY
4 # endif
5 # include <GL/glx.h>
6 # include <dlfcn.h>
7 #else
8 # include <windows.h>
9 # include <wingdi.h>
10 #endif
11
12 #include "XGUI_ViewPort.h"
13 #include "XGUI_ViewWindow.h"
14 #include "XGUI_Viewer.h"
15
16 #include <QGuiApplication>
17 #include <QPaintEvent>
18 #include <QPainter>
19
20 #include <V3d_OrthographicView.hxx>
21 #include <V3d_PerspectiveView.hxx>
22 #include <Visual3d_View.hxx>
23
24 #ifdef WIN32
25 #include <WNT_Window.hxx>
26 #else
27 #include <Xw_Window.hxx>
28 #endif
29
30 #include <GL/gl.h>
31
32
33 /*!
34     Create native view window for CasCade view [ static ]
35 */
36 Handle(Aspect_Window) CreateCasWindow( const Handle(V3d_View)& view, WId winId )
37 {
38   Aspect_Handle aWindowHandle = (Aspect_Handle)winId;
39 #ifdef WIN32
40   Handle(WNT_Window) viewWindow = new WNT_Window( aWindowHandle );
41 #else
42   Handle(Aspect_DisplayConnection) aDispConnection = view->Viewer()->Driver()->GetDisplayConnection();
43   Handle(Xw_Window) viewWindow = new Xw_Window( aDispConnection, aWindowHandle );
44 #endif
45   return viewWindow;
46 }
47
48
49
50 class OpenGLUtils_FrameBuffer
51 {
52 public:
53   OpenGLUtils_FrameBuffer();
54   ~OpenGLUtils_FrameBuffer();
55
56   bool init( const GLsizei&, const GLsizei& );
57   void release();
58
59   void bind();
60   void unbind();
61
62 private:
63   GLuint textureId;
64   GLuint fboId;
65   GLuint rboId;
66 };
67
68
69 #ifndef APIENTRY
70 #define APIENTRY
71 #endif
72 #ifndef APIENTRYP
73 #define APIENTRYP APIENTRY *
74 #endif
75
76 #ifndef GL_FRAMEBUFFER_EXT
77 #define GL_FRAMEBUFFER_EXT                0x8D40
78 #endif
79
80 #ifndef GL_RENDERBUFFER_EXT
81 #define GL_RENDERBUFFER_EXT               0x8D41
82 #endif
83
84 #ifndef GL_COLOR_ATTACHMENT0_EXT
85 #define GL_COLOR_ATTACHMENT0_EXT          0x8CE0
86 #endif
87
88 #ifndef GL_DEPTH_ATTACHMENT_EXT
89 #define GL_DEPTH_ATTACHMENT_EXT           0x8D00
90 #endif
91
92 #ifndef GL_FRAMEBUFFER_COMPLETE_EXT
93 #define GL_FRAMEBUFFER_COMPLETE_EXT       0x8CD5
94 #endif
95
96 typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSEXTPROC) (GLsizei n, GLuint *framebuffers);
97 typedef void (APIENTRYP PFNGLBINDFRAMEBUFFEREXTPROC) (GLenum target, GLuint framebuffer);
98 typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
99 typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) (GLenum target);
100 typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSEXTPROC) (GLsizei n, const GLuint *framebuffers);
101 typedef void (APIENTRYP PFNGLGENRENDERBUFFERSEXTPROC) (GLsizei n, GLuint *renderbuffers);
102 typedef void (APIENTRYP PFNGLBINDRENDERBUFFEREXTPROC) (GLenum target, GLuint renderbuffer);
103 typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
104 typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
105 typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSEXTPROC) (GLsizei n, const GLuint *renderbuffers);
106
107 static PFNGLGENFRAMEBUFFERSEXTPROC vglGenFramebuffersEXT = NULL;
108 static PFNGLBINDFRAMEBUFFEREXTPROC vglBindFramebufferEXT = NULL;
109 static PFNGLFRAMEBUFFERTEXTURE2DEXTPROC vglFramebufferTexture2DEXT = NULL;
110 static PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC vglCheckFramebufferStatusEXT = NULL;
111 static PFNGLDELETEFRAMEBUFFERSEXTPROC vglDeleteFramebuffersEXT = NULL;
112 static PFNGLGENRENDERBUFFERSEXTPROC vglGenRenderbuffersEXT = NULL;
113 static PFNGLBINDRENDERBUFFEREXTPROC vglBindRenderbufferEXT = NULL;
114 static PFNGLRENDERBUFFERSTORAGEEXTPROC vglRenderbufferStorageEXT = NULL;
115 static PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC vglFramebufferRenderbufferEXT = NULL;
116 static PFNGLDELETERENDERBUFFERSEXTPROC vglDeleteRenderbuffersEXT = NULL;
117
118 #ifndef WIN32
119 #define GL_GetProcAddress( x ) glXGetProcAddressARB( (const GLubyte*)x )
120 #else
121 #define GL_GetProcAddress( x ) wglGetProcAddress( (const LPCSTR)x )
122 #endif
123
124 bool InitializeEXT()
125 {
126   vglGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC)GL_GetProcAddress( "glGenFramebuffersEXT" );
127   vglBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)GL_GetProcAddress( "glBindFramebufferEXT" );
128   vglFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)GL_GetProcAddress( "glFramebufferTexture2DEXT" );
129   vglCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)GL_GetProcAddress( "glCheckFramebufferStatusEXT" );
130   vglDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC)GL_GetProcAddress( "glDeleteFramebuffersEXT" );
131   vglGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC)GL_GetProcAddress( "glGenRenderbuffersEXT" );
132   vglBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC)GL_GetProcAddress( "glBindRenderbufferEXT" );
133   vglRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC)GL_GetProcAddress( "glRenderbufferStorageEXT" );
134   vglFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)GL_GetProcAddress( "glFramebufferRenderbufferEXT" );
135   vglDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC)GL_GetProcAddress( "glDeleteRenderbuffersEXT" );
136
137   bool ok = vglGenFramebuffersEXT && vglBindFramebufferEXT && vglFramebufferTexture2DEXT &&
138             vglCheckFramebufferStatusEXT && vglDeleteFramebuffersEXT && vglGenRenderbuffersEXT &&
139             vglBindRenderbufferEXT && vglRenderbufferStorageEXT && vglFramebufferRenderbufferEXT &&
140             vglDeleteRenderbuffersEXT;
141
142   return ok;
143 }
144
145 static bool IsEXTInitialized = InitializeEXT();
146
147 OpenGLUtils_FrameBuffer::OpenGLUtils_FrameBuffer()
148   : textureId( 0 ),
149     fboId( 0 ),
150     rboId( 0 )
151 {
152 }
153
154 OpenGLUtils_FrameBuffer::~OpenGLUtils_FrameBuffer()
155 {
156   release();
157 }
158
159 bool OpenGLUtils_FrameBuffer::init( const GLsizei& xSize, const GLsizei& ySize )
160 {
161   char* ext = (char*)glGetString( GL_EXTENSIONS );
162   if( !IsEXTInitialized ||
163       strstr( ext, "GL_EXT_framebuffer_object" ) == NULL )
164   {
165     qDebug( "Initializing OpenGL FrameBuffer extension failed" );
166     return false;
167   }
168
169   // create a texture object
170   glEnable( GL_TEXTURE_2D );
171   glGenTextures( 1, &textureId );
172   glBindTexture( GL_TEXTURE_2D, textureId );
173   glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
174   glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
175   glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, xSize, ySize, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL );
176   glBindTexture( GL_TEXTURE_2D, 0 );
177
178   // create a renderbuffer object to store depth info
179   vglGenRenderbuffersEXT( 1, &rboId );
180   vglBindRenderbufferEXT( GL_RENDERBUFFER_EXT, rboId );
181   vglRenderbufferStorageEXT( GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, xSize, ySize );
182   vglBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 0 );
183
184   // create a framebuffer object
185   vglGenFramebuffersEXT( 1, &fboId );
186   vglBindFramebufferEXT( GL_FRAMEBUFFER_EXT, fboId );
187
188   // attach the texture to FBO color attachment point
189   vglFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, textureId, 0 );
190
191   // attach the renderbuffer to depth attachment point
192   vglFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, rboId );
193
194   // check FBO status
195   GLenum status = vglCheckFramebufferStatusEXT( GL_FRAMEBUFFER_EXT );
196
197   // Unbind FBO
198   vglBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 );
199
200   return status == GL_FRAMEBUFFER_COMPLETE_EXT;
201 }
202
203 void OpenGLUtils_FrameBuffer::release()
204 {
205   if( !IsEXTInitialized )
206     return;
207
208   glDeleteTextures( 1, &textureId );
209   textureId = 0;
210
211   vglDeleteFramebuffersEXT( 1, &fboId );
212   fboId = 0;
213
214   vglDeleteRenderbuffersEXT( 1, &rboId );
215   rboId = 0;
216 }
217
218 void OpenGLUtils_FrameBuffer::bind()
219 {
220   if( !IsEXTInitialized )
221     return;
222
223   vglBindFramebufferEXT( GL_FRAMEBUFFER_EXT, fboId );
224 }
225
226 void OpenGLUtils_FrameBuffer::unbind()
227 {
228   if( !IsEXTInitialized )
229     return;
230
231   vglBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 );
232 }
233
234
235
236 //************************************************************************
237 //************************************************************************
238 //************************************************************************
239 XGUI_ViewPort::XGUI_ViewPort(XGUI_ViewWindow* theParent, 
240                              const Handle(V3d_Viewer)& theViewer, 
241                              V3d_TypeOfView theType) :
242 QWidget(theParent), 
243     myPaintersRedrawing(false)
244 {
245     setMouseTracking( true );
246     setBackgroundRole( QPalette::NoRole ); 
247
248     // set focus policy to threat QContextMenuEvent from keyboard  
249     setFocusPolicy( Qt::StrongFocus );
250     setAttribute( Qt::WA_PaintOnScreen );
251     setAttribute( Qt::WA_NoSystemBackground );
252
253     if ( theType == V3d_ORTHOGRAPHIC ) {
254         myOrthoView = new V3d_OrthographicView( theViewer );
255         myActiveView = myOrthoView;
256         myPerspView = 0;
257     } else {
258         myPerspView = new V3d_PerspectiveView( theViewer );
259         myActiveView = myPerspView;
260     }
261   //setBackground( Qtx::BackgroundData( Qt::black ) ); // set default background
262 }
263
264 //***********************************************
265 XGUI_ViewPort::~XGUI_ViewPort()
266 {
267 }
268
269 //***********************************************
270 bool XGUI_ViewPort::mapView( const Handle(V3d_View)& theView)
271 {
272     if ( !setWindow( theView ) )
273         return false;
274
275     if ( !mapped( theView ) ) {
276         theView->SetWindow( myWindow );
277         if ( theView != activeView() )
278             theView->View()->Deactivate();
279     }
280
281     /* create static trihedron (16551: EDF PAL 501) */
282     //OCCViewer_ViewWindow* aVW = dynamic_cast<OCCViewer_ViewWindow*>( parentWidget()->parentWidget()->parentWidget() );
283     //if ( aVW ) {
284     //    OCCViewer_Viewer* aViewModel = dynamic_cast<OCCViewer_Viewer*>( aVW->getViewManager()->getViewModel() );
285     //    if ( aViewModel && aViewModel->isStaticTrihedronDisplayed() ){
286     //theView->ZBufferTriedronSetup();
287     theView->TriedronDisplay( Aspect_TOTP_LEFT_LOWER, Quantity_NOC_WHITE, 0.05, V3d_ZBUFFER );
288     //    }
289     //}
290
291     emit( vpMapped() );
292
293     return true;
294 }
295
296 //***********************************************
297 bool XGUI_ViewPort::setWindow( const Handle(V3d_View)& theView)
298 {
299     if ( !myWindow.IsNull() )
300         return true;
301
302     if ( theView.IsNull() )
303         return false;
304
305     attachWindow( theView, CreateCasWindow( theView, winId() ) );
306
307   myWindow = theView->Window();
308   return !myWindow.IsNull();
309 }
310
311 //***********************************************
312 bool XGUI_ViewPort::mapped( const Handle(V3d_View)& theView) const
313 {
314   return ( !theView.IsNull() && theView->View()->IsDefined() );
315 }
316
317 //***********************************************
318 void XGUI_ViewPort::updateBackground()
319 {
320 }
321
322 //***********************************************
323 void XGUI_ViewPort::attachWindow( const Handle(V3d_View)& theView, const Handle(Aspect_Window)& theWnd)
324 {
325     if (!theView.IsNull()) {
326         theView->SetWindow( theWnd );
327         updateBackground();
328     }
329 }
330
331 //***********************************************
332 void XGUI_ViewPort::paintEvent( QPaintEvent* theEvent)
333 {
334 #ifndef WIN32
335     /* X11 : map before show doesn't work */
336     if ( !mapped( activeView() ) )
337         mapView( activeView() );
338 #endif
339     if ( !myWindow.IsNull() ) {
340         //QGuiApplication::sync();
341         QRect rc = theEvent->rect();
342         //if ( !myPaintersRedrawing ) {
343             //activeView()->Redraw();
344             activeView()->Redraw( rc.x(), rc.y(), rc.width(), rc.height() );
345         //}
346     }
347     //if ( myPaintersRedrawing ) {
348     //    QPainter p( this );
349     //    //emit vpDrawExternal( &p );
350     //    myPaintersRedrawing = false;
351     //}
352 }
353
354 //***********************************************
355 void XGUI_ViewPort::resizeEvent( QResizeEvent* )
356 {
357 #ifdef WIN32
358     /* Win32 : map before first show to avoid flicker */
359     if ( !mapped( activeView() ) )
360         mapView( activeView() );
361 #endif
362     //QGuiApplication::sync();
363     if ( !activeView().IsNull() )
364         activeView()->MustBeResized();
365 }
366
367 //***********************************************
368 QImage XGUI_ViewPort::dumpView()
369 {
370     Handle(V3d_View) view = getView();
371     if ( view.IsNull() )
372         return QImage();
373   
374     int aWidth = width();
375     int aHeight = height();
376     //QApplication::syncX();
377     view->Redraw(); // In order to reactivate GL context
378     //view->Update();
379
380     OpenGLUtils_FrameBuffer aFrameBuffer;
381     if( aFrameBuffer.init( aWidth, aHeight ) )
382     {
383         QImage anImage( aWidth, aHeight, QImage::Format_RGB32 );
384    
385         glPushAttrib( GL_VIEWPORT_BIT );
386         glViewport( 0, 0, aWidth, aHeight );
387         aFrameBuffer.bind();
388
389         // draw scene
390         view->Redraw();
391
392         aFrameBuffer.unbind();
393         glPopAttrib();
394
395         aFrameBuffer.bind();
396         glReadPixels( 0, 0, aWidth, aHeight, GL_RGBA, GL_UNSIGNED_BYTE, anImage.bits() );
397         aFrameBuffer.unbind();
398
399         anImage = anImage.rgbSwapped();
400         anImage = anImage.mirrored();
401         return anImage;
402     }
403     // if frame buffers are unsupported, use old functionality
404     //view->Redraw();
405
406     unsigned char* data = new unsigned char[ aWidth*aHeight*4 ];
407
408     QPoint p = mapFromParent(geometry().topLeft());
409
410     glReadPixels( p.x(), p.y(), aWidth, aHeight, GL_RGBA, GL_UNSIGNED_BYTE,
411                 data);
412
413     QImage anImage( data, aWidth, aHeight, QImage::Format_ARGB32 );
414     anImage = anImage.mirrored();
415     anImage = anImage.rgbSwapped();
416     return anImage;
417 }