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