Salome HOME
Merge branch 'master' of newgeom:newgeom
[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
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   if (activeView().IsNull())
334     return;
335   if (!myBackground.isValid())
336     return;
337
338   // VSR: Important note on below code.
339   // In OCCT (in version 6.5.2), things about the background drawing
340   // are not straightforward and not clearly understandable:
341   // - Horizontal gradient is drawn vertically (!), well ok, from top side to bottom one.
342   // - Vertical gradient is drawn horizontally (!), from right side to left one (!!!).
343   // - First and second diagonal gradients are confused.
344   // - Image texture, once set, can not be removed (!).
345   // - Texture image fill mode Aspect_FM_NONE is not taken into account (and means the same
346   //   as Aspect_FM_CENTERED).
347   // - The only way to cancel gradient background (and get back to single colored) is to
348   //   set gradient background style to Aspect_GFM_NONE while passing two colors is also needed
349   //   (see V3d_View::SetBgGradientColors() function).
350   // - Also, it is impossible to draw texture image above the gradiented background (only above
351   //   single-colored).
352   // In OCCT 6.5.3 all above mentioned problems are fixed; so, above comment should be removed as soon
353   // as SALOME is migrated to OCCT 6.5.3. The same concerns #ifdef statements in the below code
354   switch(myBackground.mode()) {
355   case XGUI::ColorBackground: {
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     QColor c1, c2;
372     int type = myBackground.gradient(c1, c2);
373     if (c1.isValid() && type >= XGUI::HorizontalGradient && type <= XGUI::LastGradient) {
374       // Unset texture should be done here
375       // ...
376       // Get colors and set-up gradiented background
377       if (!c2.isValid())
378         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,
385         Standard_True);
386         break;
387       case XGUI::VerticalGradient:
388         activeView()->SetBgGradientColors(qCol1, qCol2, Aspect_GFM_VER,
389         Standard_True);
390         break;
391       case XGUI::Diagonal1Gradient:
392         activeView()->SetBgGradientColors(qCol1, qCol2, Aspect_GFM_DIAG1,
393         Standard_True);
394         break;
395       case XGUI::Diagonal2Gradient:
396         activeView()->SetBgGradientColors(qCol1, qCol2, Aspect_GFM_DIAG2,
397         Standard_True);
398         break;
399       case XGUI::Corner1Gradient:
400         activeView()->SetBgGradientColors(qCol1, qCol2, Aspect_GFM_CORNER1,
401         Standard_True);
402         break;
403       case XGUI::Corner2Gradient:
404         activeView()->SetBgGradientColors(qCol1, qCol2, Aspect_GFM_CORNER2,
405         Standard_True);
406         break;
407       case XGUI::Corner3Gradient:
408         activeView()->SetBgGradientColors(qCol1, qCol2, Aspect_GFM_CORNER3,
409         Standard_True);
410         break;
411       case XGUI::Corner4Gradient:
412         activeView()->SetBgGradientColors(qCol1, qCol2, Aspect_GFM_CORNER4,
413         Standard_True);
414         break;
415       default:
416         break;
417       }
418     }
419     break;
420   }
421   case XGUI::CustomGradientBackground:
422     // NOT IMPLEMENTED YET
423     break;
424   default:
425     break;
426   }
427   // VSR: In OCCT before v6.5.3 below code can't be used because of very ugly bug - it has been impossible to
428   // clear the background texture image as soon as it was once set to the viewer.
429   if (myBackground.isTextureShown()) {
430     QString fileName;
431     int textureMode = myBackground.texture(fileName);
432     QFileInfo fi(fileName);
433     if (!fileName.isEmpty() && fi.exists()) {
434       // set texture image: file name and fill mode
435       switch(textureMode) {
436       case XGUI::CenterTexture:
437         activeView()->SetBackgroundImage(fi.absoluteFilePath().toLatin1().constData(),
438                                          Aspect_FM_CENTERED);
439         break;
440       case XGUI::TileTexture:
441         activeView()->SetBackgroundImage(fi.absoluteFilePath().toLatin1().constData(),
442                                          Aspect_FM_TILED);
443         break;
444       case XGUI::StretchTexture:
445         activeView()->SetBackgroundImage(fi.absoluteFilePath().toLatin1().constData(),
446                                          Aspect_FM_STRETCH);
447         break;
448       default:
449         break;
450       }
451       activeView()->Update();
452     }
453   }
454 }
455
456 //***********************************************
457 void XGUI_ViewPort::attachWindow(const Handle(V3d_View)& theView,
458                                  const Handle(Aspect_Window)& theWnd)
459 {
460   if (!theView.IsNull()) {
461     theView->SetWindow(theWnd);
462     updateBackground();
463   }
464 }
465
466 //***********************************************
467 void XGUI_ViewPort::paintEvent(QPaintEvent* theEvent)
468 {
469 #ifndef WIN32
470   /* X11 : map before show doesn't work */
471   if ( !mapped( activeView() ) )
472   mapView( activeView() );
473 #endif
474   if (!myWindow.IsNull()) {
475     //QGuiApplication::sync();
476     QRect rc = theEvent->rect();
477     //if ( !myPaintersRedrawing ) {
478     //activeView()->Redraw();
479     activeView()->Redraw(rc.x(), rc.y(), rc.width(), rc.height());
480     emit vpUpdated();
481     //}
482   }
483   //if ( myPaintersRedrawing ) {
484   //    QPainter p( this );
485   //    //emit vpDrawExternal( &p );
486   //    myPaintersRedrawing = false;
487   //}
488 }
489
490 //***********************************************
491 void XGUI_ViewPort::resizeEvent(QResizeEvent*)
492 {
493 #ifdef WIN32
494   /* Win32 : map before first show to avoid flicker */
495   if (!mapped(activeView()))
496     mapView(activeView());
497 #endif
498   //QGuiApplication::sync();
499   if (!activeView().IsNull())
500     activeView()->MustBeResized();
501 }
502
503 //***********************************************
504 QImage XGUI_ViewPort::dumpView(QRect theRect, bool toUpdate)
505 {
506   Handle(V3d_View) view = getView();
507   if (view.IsNull())
508     return QImage();
509
510   int aWidth;
511   int aHeight;
512   if (theRect.isNull()) {
513     aWidth = width();
514     aHeight = height();
515   } else {
516     aWidth = theRect.width();
517     aHeight = theRect.height();
518   }
519   //QApplication::syncX();
520
521   OpenGLUtils_FrameBuffer aFrameBuffer;
522   if (aFrameBuffer.init(aWidth, aHeight)) {
523     QImage anImage(aWidth, aHeight, QImage::Format_RGB32);
524
525     glPushAttrib (GL_VIEWPORT_BIT);
526     glViewport(0, 0, aWidth, aHeight);
527     aFrameBuffer.bind();
528
529     // draw scene
530     if (toUpdate) {
531       if (theRect.isNull())
532         view->Redraw();
533       else
534         view->Redraw(theRect.x(), theRect.y(), theRect.width(), theRect.height());
535     }
536     aFrameBuffer.unbind();
537     glPopAttrib();
538
539     aFrameBuffer.bind();
540     if (theRect.isNull())
541       glReadPixels(0, 0, aWidth, aHeight, GL_RGBA, GL_UNSIGNED_BYTE, anImage.bits());
542     else
543       glReadPixels(theRect.x(), theRect.y(), aWidth, aHeight, GL_RGBA, GL_UNSIGNED_BYTE,
544                    anImage.bits());
545     aFrameBuffer.unbind();
546
547     anImage = anImage.rgbSwapped();
548     anImage = anImage.mirrored();
549     return anImage;
550   }
551   // if frame buffers are unsupported, use old functionality
552   unsigned char* data = new unsigned char[aWidth * aHeight * 4];
553
554   QPoint p;
555   if (theRect.isNull()) {
556     if (toUpdate)
557       view->Redraw();
558     p = mapFromParent(geometry().topLeft());
559   } else {
560     if (toUpdate)
561       view->Redraw(theRect.x(), theRect.y(), theRect.width(), theRect.height());
562     p = theRect.topLeft();
563   }
564   glReadPixels(p.x(), p.y(), aWidth, aHeight, GL_RGBA, GL_UNSIGNED_BYTE, data);
565
566   QImage anImage(data, aWidth, aHeight, QImage::Format_ARGB32);
567   anImage = anImage.mirrored();
568   anImage = anImage.rgbSwapped();
569   return anImage;
570 }
571
572 /*!
573  Inits 'rotation' transformation.
574  */
575 void XGUI_ViewPort::startRotation(int x, int y, int theRotationPointType,
576                                   const gp_Pnt& theSelectedPoint)
577 {
578   if (!activeView().IsNull()) {
579     switch(theRotationPointType) {
580     case XGUI::GRAVITY:
581       activeView()->StartRotation(x, y, 0.45);
582       break;
583     case XGUI::SELECTED:
584       sx = x;
585       sy = y;
586
587       double X, Y;
588       activeView()->Size(X, Y);
589       rx = Standard_Real(activeView()->Convert(X));
590       ry = Standard_Real(activeView()->Convert(Y));
591
592       activeView()->Rotate(0., 0., 0., theSelectedPoint.X(), theSelectedPoint.Y(),
593                            theSelectedPoint.Z(),
594                            Standard_True);
595
596       Quantity_Ratio zRotationThreshold;
597       zRotation = Standard_False;
598       zRotationThreshold = 0.45;
599       if (zRotationThreshold > 0.) {
600         Standard_Real dx = Abs(sx - rx / 2.);
601         Standard_Real dy = Abs(sy - ry / 2.);
602         Standard_Real dd = zRotationThreshold * (rx + ry) / 2.;
603         if (dx > dd || dy > dd)
604           zRotation = Standard_True;
605       }
606       break;
607     default:
608       break;
609     }
610     activeView()->DepthFitAll();
611   }
612 }
613
614 /*!
615  Rotates the viewport. 
616  */
617 void XGUI_ViewPort::rotate(int x, int y, int theRotationPointType, const gp_Pnt& theSelectedPoint)
618 {
619   if (!activeView().IsNull()) {
620     switch(theRotationPointType) {
621     case XGUI::GRAVITY:
622       activeView()->Rotation(x, y);
623       break;
624     case XGUI::SELECTED:
625       double dx, dy, dz;
626       if (zRotation) {
627         dz = atan2(Standard_Real(x) - rx / 2., ry / 2. - Standard_Real(y))
628             - atan2(sx - rx / 2., ry / 2. - sy);
629         dx = dy = 0.;
630       } else {
631         dx = (Standard_Real(x) - sx) * M_PI / rx;
632         dy = (sy - Standard_Real(y)) * M_PI / ry;
633         dz = 0.;
634       }
635
636       activeView()->Rotate(dx, dy, dz, theSelectedPoint.X(), theSelectedPoint.Y(),
637                            theSelectedPoint.Z(),
638                            Standard_False);
639       break;
640     default:
641       break;
642     }
643     emit vpTransformed();
644   }
645   //  setZSize( getZSize() );
646 }
647
648 /*!
649  Resets the viewport after 'rotation'. 
650  */
651 void XGUI_ViewPort::endRotation()
652 {
653   if (!activeView().IsNull()) {
654     activeView()->ZFitAll(1.);
655     activeView()->SetZSize(0.);
656     activeView()->Update();
657     emit vpTransformed();
658   }
659 }
660
661 /*!
662  Inits 'zoom' transformation.
663  */
664 void XGUI_ViewPort::startZoomAtPoint(int x, int y)
665 {
666   if (!activeView().IsNull()/* && isAdvancedZoomingEnabled() */)
667     activeView()->StartZoomAtPoint(x, y);
668 }
669
670 /*!
671  Centers the viewport. 
672  */
673 void XGUI_ViewPort::setCenter(int x, int y)
674 {
675   if (!activeView().IsNull()) {
676     activeView()->Place(x, y, myScale);
677     emit vpTransformed();
678   }
679 }
680
681 /*!
682  Called at 'pan' transformation. 
683  */
684 void XGUI_ViewPort::pan(int dx, int dy)
685 {
686   if (!activeView().IsNull()) {
687     activeView()->Pan(dx, dy, 1.0);
688     emit vpTransformed();
689   }
690 }
691
692 /*!
693  Called at 'window fit' transformation.
694  */
695 void XGUI_ViewPort::fitRect(const QRect& rect)
696 {
697   if (!activeView().IsNull()) {
698     activeView()->WindowFit(rect.left(), rect.top(), rect.right(), rect.bottom());
699     emit vpTransformed();
700   }
701 }
702
703 /*!
704  Called at 'zoom' transformation.
705  */
706 void XGUI_ViewPort::zoom(int x0, int y0, int x, int y)
707 {
708   if (!activeView().IsNull()) {
709     if (isAdvancedZoomingEnabled())
710       activeView()->ZoomAtPoint(x0, y0, x, y);
711     else
712       activeView()->Zoom(x0 + y0, 0, x + y, 0);
713     emit vpTransformed();
714   }
715 }
716
717 /*!
718  Sets the background data
719  */
720 void XGUI_ViewPort::setBackground(const XGUI_ViewBackground& bgData)
721 {
722   if (bgData.isValid()) {
723     myBackground = bgData;
724     updateBackground();
725     emit vpChangeBackground(myBackground);
726   }
727 }
728
729 void XGUI_ViewPort::fitAll(bool theKeepScale, bool theWithZ, bool theUpd)
730 {
731   if ( activeView().IsNull() )
732     return;
733
734   if ( theKeepScale )
735     myScale = activeView()->Scale();
736
737   Standard_Real aMargin = 0.01;
738   activeView()->FitAll( aMargin, theWithZ, theUpd );
739   activeView()->SetZSize(0.);
740   emit vpTransformed( );
741 }
742
743 void XGUI_ViewPort::syncronizeWith( const XGUI_ViewPort* ref )
744 {
745   Handle(V3d_View) refView = ref->getView();
746   Handle(V3d_View) tgtView = getView();
747
748   /*  The following params are copied:
749       - view type( ortho/persp )
750       - position of view point
751       - orientation of high point
752       - position of the eye
753       - projection vector
754       - view center ( 2D )
755       - view twist
756       - view scale
757   */
758
759   /* we'll update after setting all params */
760   tgtView->SetImmediateUpdate( Standard_False );
761
762   /* perspective */
763   if ( refView->Type() == V3d_PERSPECTIVE )
764     tgtView->SetFocale( refView->Focale() );
765
766   /* copy params */
767   Standard_Real x, y, z;
768   refView->At( x, y, z ); tgtView->SetAt( x, y, z );
769   refView->Up( x, y, z ); tgtView->SetUp( x, y, z );
770   refView->Eye( x, y, z ); tgtView->SetEye( x, y, z );
771   refView->Proj( x, y, z ); tgtView->SetProj( x, y, z );
772   refView->Center( x, y ); tgtView->SetCenter( x, y );
773   tgtView->SetScale( refView->Scale() );
774   tgtView->SetTwist( refView->Twist() );
775
776   /* update */
777   tgtView->Update();
778   tgtView->SetImmediateUpdate( Standard_True );
779 }