]> SALOME platform Git repositories - modules/shaper.git/blob - src/XGUI/XGUI_ViewPort.cpp
Salome HOME
Mouse interaction with Viewer is added
[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 #include "XGUI_Constants.h"
16
17 #include <QGuiApplication>
18 #include <QPaintEvent>
19 #include <QPainter>
20
21 #include <V3d_OrthographicView.hxx>
22 #include <V3d_PerspectiveView.hxx>
23 #include <Visual3d_View.hxx>
24
25 #ifdef WIN32
26 #include <WNT_Window.hxx>
27 #else
28 #include <Xw_Window.hxx>
29 #endif
30
31 #include <GL/gl.h>
32
33
34 static double rx = 0.;
35 static double ry = 0.;
36 static int sx = 0;
37 static int sy = 0;
38 static Standard_Boolean zRotation = Standard_False;
39
40
41
42 /*!
43     Create native view window for CasCade view [ static ]
44 */
45 Handle(Aspect_Window) CreateCasWindow( const Handle(V3d_View)& view, WId winId )
46 {
47   Aspect_Handle aWindowHandle = (Aspect_Handle)winId;
48 #ifdef WIN32
49   Handle(WNT_Window) viewWindow = new WNT_Window( aWindowHandle );
50 #else
51   Handle(Aspect_DisplayConnection) aDispConnection = view->Viewer()->Driver()->GetDisplayConnection();
52   Handle(Xw_Window) viewWindow = new Xw_Window( aDispConnection, aWindowHandle );
53 #endif
54   return viewWindow;
55 }
56
57
58
59 class OpenGLUtils_FrameBuffer
60 {
61 public:
62   OpenGLUtils_FrameBuffer();
63   ~OpenGLUtils_FrameBuffer();
64
65   bool init( const GLsizei&, const GLsizei& );
66   void release();
67
68   void bind();
69   void unbind();
70
71 private:
72   GLuint textureId;
73   GLuint fboId;
74   GLuint rboId;
75 };
76
77
78 #ifndef APIENTRY
79 #define APIENTRY
80 #endif
81 #ifndef APIENTRYP
82 #define APIENTRYP APIENTRY *
83 #endif
84
85 #ifndef GL_FRAMEBUFFER_EXT
86 #define GL_FRAMEBUFFER_EXT                0x8D40
87 #endif
88
89 #ifndef GL_RENDERBUFFER_EXT
90 #define GL_RENDERBUFFER_EXT               0x8D41
91 #endif
92
93 #ifndef GL_COLOR_ATTACHMENT0_EXT
94 #define GL_COLOR_ATTACHMENT0_EXT          0x8CE0
95 #endif
96
97 #ifndef GL_DEPTH_ATTACHMENT_EXT
98 #define GL_DEPTH_ATTACHMENT_EXT           0x8D00
99 #endif
100
101 #ifndef GL_FRAMEBUFFER_COMPLETE_EXT
102 #define GL_FRAMEBUFFER_COMPLETE_EXT       0x8CD5
103 #endif
104
105 typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSEXTPROC) (GLsizei n, GLuint *framebuffers);
106 typedef void (APIENTRYP PFNGLBINDFRAMEBUFFEREXTPROC) (GLenum target, GLuint framebuffer);
107 typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
108 typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) (GLenum target);
109 typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSEXTPROC) (GLsizei n, const GLuint *framebuffers);
110 typedef void (APIENTRYP PFNGLGENRENDERBUFFERSEXTPROC) (GLsizei n, GLuint *renderbuffers);
111 typedef void (APIENTRYP PFNGLBINDRENDERBUFFEREXTPROC) (GLenum target, GLuint renderbuffer);
112 typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
113 typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
114 typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSEXTPROC) (GLsizei n, const GLuint *renderbuffers);
115
116 static PFNGLGENFRAMEBUFFERSEXTPROC vglGenFramebuffersEXT = NULL;
117 static PFNGLBINDFRAMEBUFFEREXTPROC vglBindFramebufferEXT = NULL;
118 static PFNGLFRAMEBUFFERTEXTURE2DEXTPROC vglFramebufferTexture2DEXT = NULL;
119 static PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC vglCheckFramebufferStatusEXT = NULL;
120 static PFNGLDELETEFRAMEBUFFERSEXTPROC vglDeleteFramebuffersEXT = NULL;
121 static PFNGLGENRENDERBUFFERSEXTPROC vglGenRenderbuffersEXT = NULL;
122 static PFNGLBINDRENDERBUFFEREXTPROC vglBindRenderbufferEXT = NULL;
123 static PFNGLRENDERBUFFERSTORAGEEXTPROC vglRenderbufferStorageEXT = NULL;
124 static PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC vglFramebufferRenderbufferEXT = NULL;
125 static PFNGLDELETERENDERBUFFERSEXTPROC vglDeleteRenderbuffersEXT = NULL;
126
127 #ifndef WIN32
128 #define GL_GetProcAddress( x ) glXGetProcAddressARB( (const GLubyte*)x )
129 #else
130 #define GL_GetProcAddress( x ) wglGetProcAddress( (const LPCSTR)x )
131 #endif
132
133 bool InitializeEXT()
134 {
135   vglGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC)GL_GetProcAddress( "glGenFramebuffersEXT" );
136   vglBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)GL_GetProcAddress( "glBindFramebufferEXT" );
137   vglFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)GL_GetProcAddress( "glFramebufferTexture2DEXT" );
138   vglCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)GL_GetProcAddress( "glCheckFramebufferStatusEXT" );
139   vglDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC)GL_GetProcAddress( "glDeleteFramebuffersEXT" );
140   vglGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC)GL_GetProcAddress( "glGenRenderbuffersEXT" );
141   vglBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC)GL_GetProcAddress( "glBindRenderbufferEXT" );
142   vglRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC)GL_GetProcAddress( "glRenderbufferStorageEXT" );
143   vglFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)GL_GetProcAddress( "glFramebufferRenderbufferEXT" );
144   vglDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC)GL_GetProcAddress( "glDeleteRenderbuffersEXT" );
145
146   bool ok = vglGenFramebuffersEXT && vglBindFramebufferEXT && vglFramebufferTexture2DEXT &&
147             vglCheckFramebufferStatusEXT && vglDeleteFramebuffersEXT && vglGenRenderbuffersEXT &&
148             vglBindRenderbufferEXT && vglRenderbufferStorageEXT && vglFramebufferRenderbufferEXT &&
149             vglDeleteRenderbuffersEXT;
150
151   return ok;
152 }
153
154 static bool IsEXTInitialized = InitializeEXT();
155
156 OpenGLUtils_FrameBuffer::OpenGLUtils_FrameBuffer()
157   : textureId( 0 ),
158     fboId( 0 ),
159     rboId( 0 )
160 {
161 }
162
163 OpenGLUtils_FrameBuffer::~OpenGLUtils_FrameBuffer()
164 {
165   release();
166 }
167
168 bool OpenGLUtils_FrameBuffer::init( const GLsizei& xSize, const GLsizei& ySize )
169 {
170   char* ext = (char*)glGetString( GL_EXTENSIONS );
171   if( !IsEXTInitialized ||
172       strstr( ext, "GL_EXT_framebuffer_object" ) == NULL )
173   {
174     qDebug( "Initializing OpenGL FrameBuffer extension failed" );
175     return false;
176   }
177
178   // create a texture object
179   glEnable( GL_TEXTURE_2D );
180   glGenTextures( 1, &textureId );
181   glBindTexture( GL_TEXTURE_2D, textureId );
182   glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
183   glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
184   glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, xSize, ySize, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL );
185   glBindTexture( GL_TEXTURE_2D, 0 );
186
187   // create a renderbuffer object to store depth info
188   vglGenRenderbuffersEXT( 1, &rboId );
189   vglBindRenderbufferEXT( GL_RENDERBUFFER_EXT, rboId );
190   vglRenderbufferStorageEXT( GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, xSize, ySize );
191   vglBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 0 );
192
193   // create a framebuffer object
194   vglGenFramebuffersEXT( 1, &fboId );
195   vglBindFramebufferEXT( GL_FRAMEBUFFER_EXT, fboId );
196
197   // attach the texture to FBO color attachment point
198   vglFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, textureId, 0 );
199
200   // attach the renderbuffer to depth attachment point
201   vglFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, rboId );
202
203   // check FBO status
204   GLenum status = vglCheckFramebufferStatusEXT( GL_FRAMEBUFFER_EXT );
205
206   // Unbind FBO
207   vglBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 );
208
209   return status == GL_FRAMEBUFFER_COMPLETE_EXT;
210 }
211
212 void OpenGLUtils_FrameBuffer::release()
213 {
214   if( !IsEXTInitialized )
215     return;
216
217   glDeleteTextures( 1, &textureId );
218   textureId = 0;
219
220   vglDeleteFramebuffersEXT( 1, &fboId );
221   fboId = 0;
222
223   vglDeleteRenderbuffersEXT( 1, &rboId );
224   rboId = 0;
225 }
226
227 void OpenGLUtils_FrameBuffer::bind()
228 {
229   if( !IsEXTInitialized )
230     return;
231
232   vglBindFramebufferEXT( GL_FRAMEBUFFER_EXT, fboId );
233 }
234
235 void OpenGLUtils_FrameBuffer::unbind()
236 {
237   if( !IsEXTInitialized )
238     return;
239
240   vglBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 );
241 }
242
243
244
245 //************************************************************************
246 //************************************************************************
247 //************************************************************************
248 XGUI_ViewPort::XGUI_ViewPort(XGUI_ViewWindow* theParent, 
249                              const Handle(V3d_Viewer)& theViewer, 
250                              V3d_TypeOfView theType) :
251 QWidget(theParent), 
252     myPaintersRedrawing(false),
253     myScale( 1.0 ),
254     myIsAdvancedZoomingEnabled( false )
255 {
256     setMouseTracking( true );
257     setBackgroundRole( QPalette::NoRole ); 
258
259     // set focus policy to threat QContextMenuEvent from keyboard  
260     setFocusPolicy( Qt::StrongFocus );
261     setAttribute( Qt::WA_PaintOnScreen );
262     setAttribute( Qt::WA_NoSystemBackground );
263
264     if ( theType == V3d_ORTHOGRAPHIC ) {
265         myOrthoView = new V3d_OrthographicView( theViewer );
266         myActiveView = myOrthoView;
267         myPerspView = 0;
268     } else {
269         myPerspView = new V3d_PerspectiveView( theViewer );
270         myActiveView = myPerspView;
271     }
272     myActiveView->SetSurfaceDetail(V3d_TEX_ALL);
273
274   //setBackground( Qtx::BackgroundData( Qt::black ) ); // set default background
275 }
276
277 //***********************************************
278 XGUI_ViewPort::~XGUI_ViewPort()
279 {
280 }
281
282 //***********************************************
283 bool XGUI_ViewPort::mapView( const Handle(V3d_View)& theView)
284 {
285     if ( !setWindow( theView ) )
286         return false;
287
288     if ( !mapped( theView ) ) {
289         theView->SetWindow( myWindow );
290         if ( theView != activeView() )
291             theView->View()->Deactivate();
292     }
293
294     /* create static trihedron (16551: EDF PAL 501) */
295     //OCCViewer_ViewWindow* aVW = dynamic_cast<OCCViewer_ViewWindow*>( parentWidget()->parentWidget()->parentWidget() );
296     //if ( aVW ) {
297     //    OCCViewer_Viewer* aViewModel = dynamic_cast<OCCViewer_Viewer*>( aVW->getViewManager()->getViewModel() );
298     //    if ( aViewModel && aViewModel->isStaticTrihedronDisplayed() ){
299     //theView->ZBufferTriedronSetup();
300     theView->TriedronDisplay( Aspect_TOTP_LEFT_LOWER, Quantity_NOC_WHITE, 0.05, V3d_ZBUFFER );
301     //    }
302     //}
303
304     emit( vpMapped() );
305
306     return true;
307 }
308
309 //***********************************************
310 bool XGUI_ViewPort::setWindow( const Handle(V3d_View)& theView)
311 {
312     if ( !myWindow.IsNull() )
313         return true;
314
315     if ( theView.IsNull() )
316         return false;
317
318     attachWindow( theView, CreateCasWindow( theView, winId() ) );
319
320   myWindow = theView->Window();
321   return !myWindow.IsNull();
322 }
323
324 //***********************************************
325 bool XGUI_ViewPort::mapped( const Handle(V3d_View)& theView) const
326 {
327   return ( !theView.IsNull() && theView->View()->IsDefined() );
328 }
329
330 //***********************************************
331 void XGUI_ViewPort::updateBackground()
332 {
333 }
334
335 //***********************************************
336 void XGUI_ViewPort::attachWindow( const Handle(V3d_View)& theView, const Handle(Aspect_Window)& theWnd)
337 {
338     if (!theView.IsNull()) {
339         theView->SetWindow( theWnd );
340         updateBackground();
341     }
342 }
343
344 //***********************************************
345 void XGUI_ViewPort::paintEvent( QPaintEvent* theEvent)
346 {
347 #ifndef WIN32
348     /* X11 : map before show doesn't work */
349     if ( !mapped( activeView() ) )
350         mapView( activeView() );
351 #endif
352     if ( !myWindow.IsNull() ) {
353         //QGuiApplication::sync();
354         QRect rc = theEvent->rect();
355         //if ( !myPaintersRedrawing ) {
356             //activeView()->Redraw();
357             activeView()->Redraw( rc.x(), rc.y(), rc.width(), rc.height() );
358             emit vpUpdated();
359         //}
360     }
361     //if ( myPaintersRedrawing ) {
362     //    QPainter p( this );
363     //    //emit vpDrawExternal( &p );
364     //    myPaintersRedrawing = false;
365     //}
366 }
367
368 //***********************************************
369 void XGUI_ViewPort::resizeEvent( QResizeEvent* )
370 {
371 #ifdef WIN32
372     /* Win32 : map before first show to avoid flicker */
373     if ( !mapped( activeView() ) )
374         mapView( activeView() );
375 #endif
376     //QGuiApplication::sync();
377     if ( !activeView().IsNull() )
378         activeView()->MustBeResized();
379 }
380
381 //***********************************************
382 QImage XGUI_ViewPort::dumpView(QRect theRect, bool toUpdate)
383 {
384     Handle(V3d_View) view = getView();
385     if ( view.IsNull() )
386         return QImage();
387   
388     int aWidth;
389     int aHeight; 
390     if (theRect.isNull()) {
391         aWidth = width();
392         aHeight = height();
393     } else {
394         aWidth = theRect.width();
395         aHeight = theRect.height();
396     }
397     //QApplication::syncX();
398
399     OpenGLUtils_FrameBuffer aFrameBuffer;
400     if( aFrameBuffer.init( aWidth, aHeight ) )
401     {
402         QImage anImage( aWidth, aHeight, QImage::Format_RGB32 );
403    
404         glPushAttrib( GL_VIEWPORT_BIT );
405         glViewport( 0, 0, aWidth, aHeight );
406         aFrameBuffer.bind();
407
408         // draw scene
409         if (toUpdate) {
410             if (theRect.isNull())
411                 view->Redraw();
412             else
413                 view->Redraw(theRect.x(), theRect.y(), theRect.width(), theRect.height());
414         }
415         aFrameBuffer.unbind();
416         glPopAttrib();
417
418         aFrameBuffer.bind();
419         if (theRect.isNull())
420             glReadPixels( 0, 0, aWidth, aHeight, GL_RGBA, GL_UNSIGNED_BYTE, anImage.bits() );
421         else 
422             glReadPixels( theRect.x(), theRect.y(), aWidth, aHeight, GL_RGBA, GL_UNSIGNED_BYTE, anImage.bits() );
423         aFrameBuffer.unbind();
424
425         anImage = anImage.rgbSwapped();
426         anImage = anImage.mirrored();
427         return anImage;
428     }
429     // if frame buffers are unsupported, use old functionality
430     unsigned char* data = new unsigned char[ aWidth*aHeight*4 ];
431
432     QPoint p;
433     if (theRect.isNull()) {
434         if (toUpdate)
435             view->Redraw();
436         p = mapFromParent(geometry().topLeft());
437     } else {
438         if (toUpdate)
439             view->Redraw(theRect.x(), theRect.y(), theRect.width(), theRect.height());
440         p = theRect.topLeft();
441     }
442     glReadPixels( p.x(), p.y(), aWidth, aHeight, GL_RGBA, GL_UNSIGNED_BYTE, data);
443
444     QImage anImage( data, aWidth, aHeight, QImage::Format_ARGB32 );
445     anImage = anImage.mirrored();
446     anImage = anImage.rgbSwapped();
447     return anImage;
448 }
449
450
451 /*!
452   Inits 'rotation' transformation.
453 */
454 void XGUI_ViewPort::startRotation( int x, int y,
455                                    int theRotationPointType,
456                                    const gp_Pnt& theSelectedPoint )
457 {
458   if ( !activeView().IsNull() ) {
459     switch ( theRotationPointType ) {
460     case XGUI::GRAVITY:
461       activeView()->StartRotation( x, y, 0.45 );
462       break;
463     case XGUI::SELECTED:
464       sx = x; sy = y;
465
466       double X,Y;
467       activeView()->Size(X,Y);
468       rx = Standard_Real(activeView()->Convert(X));
469       ry = Standard_Real(activeView()->Convert(Y));
470
471       activeView()->Rotate( 0., 0., 0.,
472                             theSelectedPoint.X(),theSelectedPoint.Y(), theSelectedPoint.Z(),
473                             Standard_True );
474
475       Quantity_Ratio zRotationThreshold;
476       zRotation = Standard_False;
477       zRotationThreshold = 0.45;
478       if( zRotationThreshold > 0. ) {
479         Standard_Real dx = Abs(sx - rx/2.);
480         Standard_Real dy = Abs(sy - ry/2.);
481         Standard_Real dd = zRotationThreshold * (rx + ry)/2.;
482         if( dx > dd || dy > dd ) zRotation = Standard_True;
483       }
484       break;
485     default:
486       break;
487     }
488     activeView()->DepthFitAll();
489   }
490 }
491
492 /*!
493   Rotates the viewport. 
494 */
495 void XGUI_ViewPort::rotate( int x, int y,
496                             int theRotationPointType,
497                             const gp_Pnt& theSelectedPoint )
498 {
499   if ( !activeView().IsNull() ) {
500     switch ( theRotationPointType ) {
501     case XGUI::GRAVITY:
502       activeView()->Rotation( x, y );
503       break;
504     case XGUI::SELECTED:
505       double dx, dy, dz;
506       if( zRotation ) {
507         dz = atan2(Standard_Real(x)-rx/2., ry/2.-Standard_Real(y)) -
508           atan2(sx-rx/2.,ry/2.-sy);
509         dx = dy = 0.;
510       }
511       else {
512         dx = (Standard_Real(x) - sx) * M_PI/rx;
513         dy = (sy - Standard_Real(y)) * M_PI/ry;
514         dz = 0.;
515       }
516
517       activeView()->Rotate( dx, dy, dz,
518                             theSelectedPoint.X(),theSelectedPoint.Y(), theSelectedPoint.Z(),
519                             Standard_False );
520       break;
521     default:
522       break;
523     }
524     emit vpTransformed( );
525   }
526   //  setZSize( getZSize() );
527 }
528
529 /*!
530   Resets the viewport after 'rotation'. 
531 */
532 void XGUI_ViewPort::endRotation()
533 {
534   if ( !activeView().IsNull() ) {
535     activeView()->ZFitAll(1.);
536     activeView()->SetZSize(0.);
537     activeView()->Update();
538     emit vpTransformed( );
539   }
540 }
541
542 /*!
543   Inits 'zoom' transformation.
544 */
545 void XGUI_ViewPort::startZoomAtPoint( int x, int y )
546 {
547     if ( !activeView().IsNull()/* && isAdvancedZoomingEnabled() */)
548         activeView()->StartZoomAtPoint( x, y );
549 }
550
551 /*!
552   Centers the viewport. 
553 */
554 void XGUI_ViewPort::setCenter( int x, int y )
555 {
556   if ( !activeView().IsNull() ) {
557     activeView()->Place( x, y, myScale );
558     emit vpTransformed( );
559   }
560 }
561
562 /*!
563   Called at 'pan' transformation. 
564  */
565 void XGUI_ViewPort::pan( int dx, int dy )
566 {
567   if ( !activeView().IsNull() ) {
568     activeView()->Pan( dx, dy, 1.0 );
569     emit vpTransformed( );
570   }
571 }
572
573 /*!
574   Called at 'window fit' transformation.
575 */
576 void XGUI_ViewPort::fitRect( const QRect& rect )
577 {
578   if ( !activeView().IsNull() ) {
579     activeView()->WindowFit( rect.left(), rect.top(), rect.right(), rect.bottom() );
580     emit vpTransformed( );
581   }
582 }
583
584 /*!
585   Called at 'zoom' transformation.
586 */
587 void XGUI_ViewPort::zoom( int x0, int y0, int x, int y )
588 {
589   if ( !activeView().IsNull() ) {
590     if ( isAdvancedZoomingEnabled() )
591       activeView()->ZoomAtPoint( x0, y0, x, y );
592     else
593       activeView()->Zoom( x0 + y0, 0, x + y, 0 );
594     emit vpTransformed( );
595   }
596 }