Salome HOME
abcb6a3dd59531409573a5fc42b48f5985faa761
[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 #include <QFileInfo>
21
22 #include <V3d_OrthographicView.hxx>
23 #include <V3d_PerspectiveView.hxx>
24 #include <Visual3d_View.hxx>
25
26 #ifdef WIN32
27 #include <WNT_Window.hxx>
28 #else
29 #include <Xw_Window.hxx>
30 #endif
31
32 #include <GL/gl.h>
33
34
35 static double rx = 0.;
36 static double ry = 0.;
37 static int sx = 0;
38 static int sy = 0;
39 static Standard_Boolean zRotation = Standard_False;
40
41
42
43 /*!
44     Create native view window for CasCade view [ static ]
45 */
46 Handle(Aspect_Window) CreateCasWindow( const Handle(V3d_View)& view, WId winId )
47 {
48   Aspect_Handle aWindowHandle = (Aspect_Handle)winId;
49 #ifdef WIN32
50   Handle(WNT_Window) viewWindow = new WNT_Window( aWindowHandle );
51 #else
52   Handle(Aspect_DisplayConnection) aDispConnection = view->Viewer()->Driver()->GetDisplayConnection();
53   Handle(Xw_Window) viewWindow = new Xw_Window( aDispConnection, aWindowHandle );
54 #endif
55   return viewWindow;
56 }
57
58
59
60 class OpenGLUtils_FrameBuffer
61 {
62 public:
63   OpenGLUtils_FrameBuffer();
64   ~OpenGLUtils_FrameBuffer();
65
66   bool init( const GLsizei&, const GLsizei& );
67   void release();
68
69   void bind();
70   void unbind();
71
72 private:
73   GLuint textureId;
74   GLuint fboId;
75   GLuint rboId;
76 };
77
78
79 #ifndef APIENTRY
80 #define APIENTRY
81 #endif
82 #ifndef APIENTRYP
83 #define APIENTRYP APIENTRY *
84 #endif
85
86 #ifndef GL_FRAMEBUFFER_EXT
87 #define GL_FRAMEBUFFER_EXT                0x8D40
88 #endif
89
90 #ifndef GL_RENDERBUFFER_EXT
91 #define GL_RENDERBUFFER_EXT               0x8D41
92 #endif
93
94 #ifndef GL_COLOR_ATTACHMENT0_EXT
95 #define GL_COLOR_ATTACHMENT0_EXT          0x8CE0
96 #endif
97
98 #ifndef GL_DEPTH_ATTACHMENT_EXT
99 #define GL_DEPTH_ATTACHMENT_EXT           0x8D00
100 #endif
101
102 #ifndef GL_FRAMEBUFFER_COMPLETE_EXT
103 #define GL_FRAMEBUFFER_COMPLETE_EXT       0x8CD5
104 #endif
105
106 typedef void (APIENTRYP PFNGLGENFRAMEBUFFERSEXTPROC) (GLsizei n, GLuint *framebuffers);
107 typedef void (APIENTRYP PFNGLBINDFRAMEBUFFEREXTPROC) (GLenum target, GLuint framebuffer);
108 typedef void (APIENTRYP PFNGLFRAMEBUFFERTEXTURE2DEXTPROC) (GLenum target, GLenum attachment, GLenum textarget, GLuint texture, GLint level);
109 typedef GLenum (APIENTRYP PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC) (GLenum target);
110 typedef void (APIENTRYP PFNGLDELETEFRAMEBUFFERSEXTPROC) (GLsizei n, const GLuint *framebuffers);
111 typedef void (APIENTRYP PFNGLGENRENDERBUFFERSEXTPROC) (GLsizei n, GLuint *renderbuffers);
112 typedef void (APIENTRYP PFNGLBINDRENDERBUFFEREXTPROC) (GLenum target, GLuint renderbuffer);
113 typedef void (APIENTRYP PFNGLRENDERBUFFERSTORAGEEXTPROC) (GLenum target, GLenum internalformat, GLsizei width, GLsizei height);
114 typedef void (APIENTRYP PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC) (GLenum target, GLenum attachment, GLenum renderbuffertarget, GLuint renderbuffer);
115 typedef void (APIENTRYP PFNGLDELETERENDERBUFFERSEXTPROC) (GLsizei n, const GLuint *renderbuffers);
116
117 static PFNGLGENFRAMEBUFFERSEXTPROC vglGenFramebuffersEXT = NULL;
118 static PFNGLBINDFRAMEBUFFEREXTPROC vglBindFramebufferEXT = NULL;
119 static PFNGLFRAMEBUFFERTEXTURE2DEXTPROC vglFramebufferTexture2DEXT = NULL;
120 static PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC vglCheckFramebufferStatusEXT = NULL;
121 static PFNGLDELETEFRAMEBUFFERSEXTPROC vglDeleteFramebuffersEXT = NULL;
122 static PFNGLGENRENDERBUFFERSEXTPROC vglGenRenderbuffersEXT = NULL;
123 static PFNGLBINDRENDERBUFFEREXTPROC vglBindRenderbufferEXT = NULL;
124 static PFNGLRENDERBUFFERSTORAGEEXTPROC vglRenderbufferStorageEXT = NULL;
125 static PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC vglFramebufferRenderbufferEXT = NULL;
126 static PFNGLDELETERENDERBUFFERSEXTPROC vglDeleteRenderbuffersEXT = NULL;
127
128 #ifndef WIN32
129 #define GL_GetProcAddress( x ) glXGetProcAddressARB( (const GLubyte*)x )
130 #else
131 #define GL_GetProcAddress( x ) wglGetProcAddress( (const LPCSTR)x )
132 #endif
133
134 bool InitializeEXT()
135 {
136   vglGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC)GL_GetProcAddress( "glGenFramebuffersEXT" );
137   vglBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)GL_GetProcAddress( "glBindFramebufferEXT" );
138   vglFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)GL_GetProcAddress( "glFramebufferTexture2DEXT" );
139   vglCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)GL_GetProcAddress( "glCheckFramebufferStatusEXT" );
140   vglDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC)GL_GetProcAddress( "glDeleteFramebuffersEXT" );
141   vglGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC)GL_GetProcAddress( "glGenRenderbuffersEXT" );
142   vglBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC)GL_GetProcAddress( "glBindRenderbufferEXT" );
143   vglRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC)GL_GetProcAddress( "glRenderbufferStorageEXT" );
144   vglFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)GL_GetProcAddress( "glFramebufferRenderbufferEXT" );
145   vglDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC)GL_GetProcAddress( "glDeleteRenderbuffersEXT" );
146
147   bool ok = vglGenFramebuffersEXT && vglBindFramebufferEXT && vglFramebufferTexture2DEXT &&
148             vglCheckFramebufferStatusEXT && vglDeleteFramebuffersEXT && vglGenRenderbuffersEXT &&
149             vglBindRenderbufferEXT && vglRenderbufferStorageEXT && vglFramebufferRenderbufferEXT &&
150             vglDeleteRenderbuffersEXT;
151
152   return ok;
153 }
154
155 static bool IsEXTInitialized = InitializeEXT();
156
157 OpenGLUtils_FrameBuffer::OpenGLUtils_FrameBuffer()
158   : textureId( 0 ),
159     fboId( 0 ),
160     rboId( 0 )
161 {
162 }
163
164 OpenGLUtils_FrameBuffer::~OpenGLUtils_FrameBuffer()
165 {
166   release();
167 }
168
169 bool OpenGLUtils_FrameBuffer::init( const GLsizei& xSize, const GLsizei& ySize )
170 {
171   char* ext = (char*)glGetString( GL_EXTENSIONS );
172   if( !IsEXTInitialized ||
173       strstr( ext, "GL_EXT_framebuffer_object" ) == NULL )
174   {
175     qDebug( "Initializing OpenGL FrameBuffer extension failed" );
176     return false;
177   }
178
179   // create a texture object
180   glEnable( GL_TEXTURE_2D );
181   glGenTextures( 1, &textureId );
182   glBindTexture( GL_TEXTURE_2D, textureId );
183   glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
184   glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
185   glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA8, xSize, ySize, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL );
186   glBindTexture( GL_TEXTURE_2D, 0 );
187
188   // create a renderbuffer object to store depth info
189   vglGenRenderbuffersEXT( 1, &rboId );
190   vglBindRenderbufferEXT( GL_RENDERBUFFER_EXT, rboId );
191   vglRenderbufferStorageEXT( GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT, xSize, ySize );
192   vglBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 0 );
193
194   // create a framebuffer object
195   vglGenFramebuffersEXT( 1, &fboId );
196   vglBindFramebufferEXT( GL_FRAMEBUFFER_EXT, fboId );
197
198   // attach the texture to FBO color attachment point
199   vglFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, textureId, 0 );
200
201   // attach the renderbuffer to depth attachment point
202   vglFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, rboId );
203
204   // check FBO status
205   GLenum status = vglCheckFramebufferStatusEXT( GL_FRAMEBUFFER_EXT );
206
207   // Unbind FBO
208   vglBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 );
209
210   return status == GL_FRAMEBUFFER_COMPLETE_EXT;
211 }
212
213 void OpenGLUtils_FrameBuffer::release()
214 {
215   if( !IsEXTInitialized )
216     return;
217
218   glDeleteTextures( 1, &textureId );
219   textureId = 0;
220
221   vglDeleteFramebuffersEXT( 1, &fboId );
222   fboId = 0;
223
224   vglDeleteRenderbuffersEXT( 1, &rboId );
225   rboId = 0;
226 }
227
228 void OpenGLUtils_FrameBuffer::bind()
229 {
230   if( !IsEXTInitialized )
231     return;
232
233   vglBindFramebufferEXT( GL_FRAMEBUFFER_EXT, fboId );
234 }
235
236 void OpenGLUtils_FrameBuffer::unbind()
237 {
238   if( !IsEXTInitialized )
239     return;
240
241   vglBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 );
242 }
243
244
245
246 //************************************************************************
247 //************************************************************************
248 //************************************************************************
249 XGUI_ViewPort::XGUI_ViewPort(XGUI_ViewWindow* theParent, 
250                              const Handle(V3d_Viewer)& theViewer, 
251                              V3d_TypeOfView theType) :
252 QWidget(theParent), 
253     myPaintersRedrawing(false),
254     myScale( 1.0 ),
255     myIsAdvancedZoomingEnabled( false )
256 {
257     setMouseTracking( true );
258     setBackgroundRole( QPalette::NoRole ); 
259
260     // set focus policy to threat QContextMenuEvent from keyboard  
261     setFocusPolicy( Qt::StrongFocus );
262     setAttribute( Qt::WA_PaintOnScreen );
263     setAttribute( Qt::WA_NoSystemBackground );
264
265     if ( theType == V3d_ORTHOGRAPHIC ) {
266         myOrthoView = new V3d_OrthographicView( theViewer );
267         myActiveView = myOrthoView;
268         myPerspView = 0;
269     } else {
270         myPerspView = new V3d_PerspectiveView( theViewer );
271         myActiveView = myPerspView;
272     }
273     myActiveView->SetSurfaceDetail(V3d_TEX_ALL);
274
275   //setBackground( Qtx::BackgroundData( Qt::black ) ); // set default background
276 }
277
278 //***********************************************
279 XGUI_ViewPort::~XGUI_ViewPort()
280 {
281 }
282
283 //***********************************************
284 bool XGUI_ViewPort::mapView( const Handle(V3d_View)& theView)
285 {
286     if ( !setWindow( theView ) )
287         return false;
288
289     if ( !mapped( theView ) ) {
290         theView->SetWindow( myWindow );
291         if ( theView != activeView() )
292             theView->View()->Deactivate();
293     }
294
295     /* create static trihedron (16551: EDF PAL 501) */
296     //OCCViewer_ViewWindow* aVW = dynamic_cast<OCCViewer_ViewWindow*>( parentWidget()->parentWidget()->parentWidget() );
297     //if ( aVW ) {
298     //    OCCViewer_Viewer* aViewModel = dynamic_cast<OCCViewer_Viewer*>( aVW->getViewManager()->getViewModel() );
299     //    if ( aViewModel && aViewModel->isStaticTrihedronDisplayed() ){
300     //theView->ZBufferTriedronSetup();
301     theView->TriedronDisplay( Aspect_TOTP_LEFT_LOWER, Quantity_NOC_WHITE, 0.05, V3d_ZBUFFER );
302     //    }
303     //}
304
305     emit( vpMapped() );
306
307     return true;
308 }
309
310 //***********************************************
311 bool XGUI_ViewPort::setWindow( const Handle(V3d_View)& theView)
312 {
313     if ( !myWindow.IsNull() )
314         return true;
315
316     if ( theView.IsNull() )
317         return false;
318
319     attachWindow( theView, CreateCasWindow( theView, winId() ) );
320
321   myWindow = theView->Window();
322   return !myWindow.IsNull();
323 }
324
325 //***********************************************
326 bool XGUI_ViewPort::mapped( const Handle(V3d_View)& theView) const
327 {
328   return ( !theView.IsNull() && theView->View()->IsDefined() );
329 }
330
331 //***********************************************
332 void XGUI_ViewPort::updateBackground()
333 {
334     if ( activeView().IsNull() ) return;
335     if ( !myBackground.isValid() ) return;
336
337     // VSR: Important note on below code.
338     // In OCCT (in version 6.5.2), things about the background drawing
339     // are not straightforward and not clearly understandable:
340     // - Horizontal gradient is drawn vertically (!), well ok, from top side to bottom one.
341     // - Vertical gradient is drawn horizontally (!), from right side to left one (!!!).
342     // - First and second diagonal gradients are confused.
343     // - Image texture, once set, can not be removed (!).
344     // - Texture image fill mode Aspect_FM_NONE is not taken into account (and means the same
345     //   as Aspect_FM_CENTERED).
346     // - The only way to cancel gradient background (and get back to single colored) is to
347     //   set gradient background style to Aspect_GFM_NONE while passing two colors is also needed
348     //   (see V3d_View::SetBgGradientColors() function).
349     // - Also, it is impossible to draw texture image above the gradiented background (only above
350     //   single-colored).
351     // In OCCT 6.5.3 all above mentioned problems are fixed; so, above comment should be removed as soon
352     // as SALOME is migrated to OCCT 6.5.3. The same concerns #ifdef statements in the below code
353     switch ( myBackground.mode() ) {
354     case XGUI::ColorBackground:
355         {
356             QColor c = myBackground.color();
357             if ( c.isValid() ) {
358                 // Unset texture should be done here
359                 // ...
360                 Quantity_Color qCol( c.red()/255., c.green()/255., c.blue()/255., Quantity_TOC_RGB );
361                 activeView()->SetBgGradientStyle( Aspect_GFM_NONE ); // cancel gradient background
362                 activeView()->SetBgImageStyle( Aspect_FM_NONE );     // cancel texture background
363                 // then change background color
364                 activeView()->SetBackgroundColor( qCol );
365                 // update viewer
366                 activeView()->Update();
367             }
368             break;
369         }
370     case XGUI::SimpleGradientBackground:
371         {
372             QColor c1, c2;
373             int type = myBackground.gradient( c1, c2 );
374             if ( c1.isValid() && type >= XGUI::HorizontalGradient && type <= XGUI::LastGradient ) {
375                 // Unset texture should be done here
376                 // ...
377                 // Get colors and set-up gradiented background
378                 if ( !c2.isValid() ) c2 = c1;
379                 Quantity_Color qCol1( c1.red()/255., c1.green()/255., c1.blue()/255., Quantity_TOC_RGB );
380                 Quantity_Color qCol2( c2.red()/255., c2.green()/255., c2.blue()/255., Quantity_TOC_RGB );
381                 activeView()->SetBgImageStyle( Aspect_FM_NONE );    // cancel texture background
382                     switch ( type ) {
383                     case XGUI::HorizontalGradient:
384                         activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_HOR, Standard_True );
385                         break;
386                     case XGUI::VerticalGradient:
387                         activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_VER, Standard_True );
388                         break;
389                     case XGUI::Diagonal1Gradient:
390                         activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_DIAG1, Standard_True );
391                         break;
392                     case XGUI::Diagonal2Gradient:
393                         activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_DIAG2, Standard_True );
394                         break;
395                     case XGUI::Corner1Gradient:
396                         activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_CORNER1, Standard_True );
397                         break;
398                     case XGUI::Corner2Gradient:
399                         activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_CORNER2, Standard_True );
400                         break;
401                     case XGUI::Corner3Gradient:
402                         activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_CORNER3, Standard_True );
403                         break;
404                     case XGUI::Corner4Gradient:
405                         activeView()->SetBgGradientColors( qCol1, qCol2, Aspect_GFM_CORNER4, Standard_True );
406                         break;
407                     default:
408                         break;
409                     }
410             }
411             break;
412         }
413     case XGUI::CustomGradientBackground:
414         // NOT IMPLEMENTED YET
415         break;
416     default:
417         break;
418     }
419     // VSR: In OCCT before v6.5.3 below code can't be used because of very ugly bug - it has been impossible to
420     // clear the background texture image as soon as it was once set to the viewer.
421     if ( myBackground.isTextureShown() ) {
422         QString fileName;
423         int textureMode = myBackground.texture( fileName );
424         QFileInfo fi( fileName );
425         if ( !fileName.isEmpty() && fi.exists() ) {
426             // set texture image: file name and fill mode
427             switch ( textureMode ) {
428             case XGUI::CenterTexture:
429                     activeView()->SetBackgroundImage( fi.absoluteFilePath().toLatin1().constData(), Aspect_FM_CENTERED );
430                     break;
431             case XGUI::TileTexture:
432                     activeView()->SetBackgroundImage( fi.absoluteFilePath().toLatin1().constData(), Aspect_FM_TILED );
433                     break;
434             case XGUI::StretchTexture:
435                     activeView()->SetBackgroundImage( fi.absoluteFilePath().toLatin1().constData(), Aspect_FM_STRETCH );
436                     break;
437             default:
438                     break;
439             }
440             activeView()->Update();
441         }
442     }
443 }
444
445 //***********************************************
446 void XGUI_ViewPort::attachWindow( const Handle(V3d_View)& theView, const Handle(Aspect_Window)& theWnd)
447 {
448     if (!theView.IsNull()) {
449         theView->SetWindow( theWnd );
450         updateBackground();
451     }
452 }
453
454 //***********************************************
455 void XGUI_ViewPort::paintEvent( QPaintEvent* theEvent)
456 {
457 #ifndef WIN32
458     /* X11 : map before show doesn't work */
459     if ( !mapped( activeView() ) )
460         mapView( activeView() );
461 #endif
462     if ( !myWindow.IsNull() ) {
463         //QGuiApplication::sync();
464         QRect rc = theEvent->rect();
465         //if ( !myPaintersRedrawing ) {
466             //activeView()->Redraw();
467             activeView()->Redraw( rc.x(), rc.y(), rc.width(), rc.height() );
468             emit vpUpdated();
469         //}
470     }
471     //if ( myPaintersRedrawing ) {
472     //    QPainter p( this );
473     //    //emit vpDrawExternal( &p );
474     //    myPaintersRedrawing = false;
475     //}
476 }
477
478 //***********************************************
479 void XGUI_ViewPort::resizeEvent( QResizeEvent* )
480 {
481 #ifdef WIN32
482     /* Win32 : map before first show to avoid flicker */
483     if ( !mapped( activeView() ) )
484         mapView( activeView() );
485 #endif
486     //QGuiApplication::sync();
487     if ( !activeView().IsNull() )
488         activeView()->MustBeResized();
489 }
490
491 //***********************************************
492 QImage XGUI_ViewPort::dumpView(QRect theRect, bool toUpdate)
493 {
494     Handle(V3d_View) view = getView();
495     if ( view.IsNull() )
496         return QImage();
497   
498     int aWidth;
499     int aHeight; 
500     if (theRect.isNull()) {
501         aWidth = width();
502         aHeight = height();
503     } else {
504         aWidth = theRect.width();
505         aHeight = theRect.height();
506     }
507     //QApplication::syncX();
508
509     OpenGLUtils_FrameBuffer aFrameBuffer;
510     if( aFrameBuffer.init( aWidth, aHeight ) )
511     {
512         QImage anImage( aWidth, aHeight, QImage::Format_RGB32 );
513    
514         glPushAttrib( GL_VIEWPORT_BIT );
515         glViewport( 0, 0, aWidth, aHeight );
516         aFrameBuffer.bind();
517
518         // draw scene
519         if (toUpdate) {
520             if (theRect.isNull())
521                 view->Redraw();
522             else
523                 view->Redraw(theRect.x(), theRect.y(), theRect.width(), theRect.height());
524         }
525         aFrameBuffer.unbind();
526         glPopAttrib();
527
528         aFrameBuffer.bind();
529         if (theRect.isNull())
530             glReadPixels( 0, 0, aWidth, aHeight, GL_RGBA, GL_UNSIGNED_BYTE, anImage.bits() );
531         else 
532             glReadPixels( theRect.x(), theRect.y(), aWidth, aHeight, GL_RGBA, GL_UNSIGNED_BYTE, anImage.bits() );
533         aFrameBuffer.unbind();
534
535         anImage = anImage.rgbSwapped();
536         anImage = anImage.mirrored();
537         return anImage;
538     }
539     // if frame buffers are unsupported, use old functionality
540     unsigned char* data = new unsigned char[ aWidth*aHeight*4 ];
541
542     QPoint p;
543     if (theRect.isNull()) {
544         if (toUpdate)
545             view->Redraw();
546         p = mapFromParent(geometry().topLeft());
547     } else {
548         if (toUpdate)
549             view->Redraw(theRect.x(), theRect.y(), theRect.width(), theRect.height());
550         p = theRect.topLeft();
551     }
552     glReadPixels( p.x(), p.y(), aWidth, aHeight, GL_RGBA, GL_UNSIGNED_BYTE, data);
553
554     QImage anImage( data, aWidth, aHeight, QImage::Format_ARGB32 );
555     anImage = anImage.mirrored();
556     anImage = anImage.rgbSwapped();
557     return anImage;
558 }
559
560
561 /*!
562   Inits 'rotation' transformation.
563 */
564 void XGUI_ViewPort::startRotation( int x, int y,
565                                    int theRotationPointType,
566                                    const gp_Pnt& theSelectedPoint )
567 {
568   if ( !activeView().IsNull() ) {
569     switch ( theRotationPointType ) {
570     case XGUI::GRAVITY:
571       activeView()->StartRotation( x, y, 0.45 );
572       break;
573     case XGUI::SELECTED:
574       sx = x; sy = y;
575
576       double X,Y;
577       activeView()->Size(X,Y);
578       rx = Standard_Real(activeView()->Convert(X));
579       ry = Standard_Real(activeView()->Convert(Y));
580
581       activeView()->Rotate( 0., 0., 0.,
582                             theSelectedPoint.X(),theSelectedPoint.Y(), theSelectedPoint.Z(),
583                             Standard_True );
584
585       Quantity_Ratio zRotationThreshold;
586       zRotation = Standard_False;
587       zRotationThreshold = 0.45;
588       if( zRotationThreshold > 0. ) {
589         Standard_Real dx = Abs(sx - rx/2.);
590         Standard_Real dy = Abs(sy - ry/2.);
591         Standard_Real dd = zRotationThreshold * (rx + ry)/2.;
592         if( dx > dd || dy > dd ) zRotation = Standard_True;
593       }
594       break;
595     default:
596       break;
597     }
598     activeView()->DepthFitAll();
599   }
600 }
601
602 /*!
603   Rotates the viewport. 
604 */
605 void XGUI_ViewPort::rotate( int x, int y,
606                             int theRotationPointType,
607                             const gp_Pnt& theSelectedPoint )
608 {
609   if ( !activeView().IsNull() ) {
610     switch ( theRotationPointType ) {
611     case XGUI::GRAVITY:
612       activeView()->Rotation( x, y );
613       break;
614     case XGUI::SELECTED:
615       double dx, dy, dz;
616       if( zRotation ) {
617         dz = atan2(Standard_Real(x)-rx/2., ry/2.-Standard_Real(y)) -
618           atan2(sx-rx/2.,ry/2.-sy);
619         dx = dy = 0.;
620       }
621       else {
622         dx = (Standard_Real(x) - sx) * M_PI/rx;
623         dy = (sy - Standard_Real(y)) * M_PI/ry;
624         dz = 0.;
625       }
626
627       activeView()->Rotate( dx, dy, dz,
628                             theSelectedPoint.X(),theSelectedPoint.Y(), theSelectedPoint.Z(),
629                             Standard_False );
630       break;
631     default:
632       break;
633     }
634     emit vpTransformed( );
635   }
636   //  setZSize( getZSize() );
637 }
638
639 /*!
640   Resets the viewport after 'rotation'. 
641 */
642 void XGUI_ViewPort::endRotation()
643 {
644   if ( !activeView().IsNull() ) {
645     activeView()->ZFitAll(1.);
646     activeView()->SetZSize(0.);
647     activeView()->Update();
648     emit vpTransformed( );
649   }
650 }
651
652 /*!
653   Inits 'zoom' transformation.
654 */
655 void XGUI_ViewPort::startZoomAtPoint( int x, int y )
656 {
657     if ( !activeView().IsNull()/* && isAdvancedZoomingEnabled() */)
658         activeView()->StartZoomAtPoint( x, y );
659 }
660
661 /*!
662   Centers the viewport. 
663 */
664 void XGUI_ViewPort::setCenter( int x, int y )
665 {
666   if ( !activeView().IsNull() ) {
667     activeView()->Place( x, y, myScale );
668     emit vpTransformed( );
669   }
670 }
671
672 /*!
673   Called at 'pan' transformation. 
674  */
675 void XGUI_ViewPort::pan( int dx, int dy )
676 {
677   if ( !activeView().IsNull() ) {
678     activeView()->Pan( dx, dy, 1.0 );
679     emit vpTransformed( );
680   }
681 }
682
683 /*!
684   Called at 'window fit' transformation.
685 */
686 void XGUI_ViewPort::fitRect( const QRect& rect )
687 {
688   if ( !activeView().IsNull() ) {
689     activeView()->WindowFit( rect.left(), rect.top(), rect.right(), rect.bottom() );
690     emit vpTransformed( );
691   }
692 }
693
694 /*!
695   Called at 'zoom' transformation.
696 */
697 void XGUI_ViewPort::zoom( int x0, int y0, int x, int y )
698 {
699   if ( !activeView().IsNull() ) {
700     if ( isAdvancedZoomingEnabled() )
701       activeView()->ZoomAtPoint( x0, y0, x, y );
702     else
703       activeView()->Zoom( x0 + y0, 0, x + y, 0 );
704     emit vpTransformed( );
705   }
706 }
707
708 /*!
709   Sets the background data
710 */
711 void XGUI_ViewPort::setBackground( const XGUI_ViewBackground& bgData )
712 {
713     if ( bgData.isValid() ) {
714         myBackground = bgData;
715         updateBackground();
716         emit vpChangeBackground( myBackground );
717     }
718 }
719
720 void XGUI_ViewPort::fitAll(bool theKeepScale, bool theWithZ, bool theUpd)
721 {
722   if ( activeView().IsNull() )
723     return;
724
725   if ( theKeepScale )
726     myScale = activeView()->Scale();
727
728   Standard_Real aMargin = 0.01;
729   activeView()->FitAll( aMargin, theWithZ, theUpd );
730   activeView()->SetZSize(0.);
731   emit vpTransformed( );
732 }