Back to index

salome-gui  6.5.0
GLViewer_Widget.cxx
Go to the documentation of this file.
00001 // Copyright (C) 2007-2012  CEA/DEN, EDF R&D, OPEN CASCADE
00002 //
00003 // Copyright (C) 2003-2007  OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
00004 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
00005 //
00006 // This library is free software; you can redistribute it and/or
00007 // modify it under the terms of the GNU Lesser General Public
00008 // License as published by the Free Software Foundation; either
00009 // version 2.1 of the License.
00010 //
00011 // This library is distributed in the hope that it will be useful,
00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014 // Lesser General Public License for more details.
00015 //
00016 // You should have received a copy of the GNU Lesser General Public
00017 // License along with this library; if not, write to the Free Software
00018 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
00019 //
00020 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
00021 //
00022 
00023 #include "GLViewer_Widget.h"
00024 #include "GLViewer_ViewPort2d.h"
00025 #include "GLViewer_Viewer2d.h"
00026 #include "GLViewer_Grid.h"
00027 #include "GLViewer_CoordSystem.h"
00028 #include "GLViewer_ViewFrame.h"
00029 
00030 #include <cmath>
00031 
00032 #include <QEvent>
00033 #include <QPaintEvent>
00034 #include <QRect>
00035 #include <QFile>
00036 #include <QImage>
00037 #include <QApplication>
00038 #include <QToolTip>
00039 
00044 GLViewer_Widget::GLViewer_Widget( QWidget* parent, const char* name ):
00045 QGLWidget( parent, 0/*, WRepaintNoErase | WResizeNoErase*/ )
00046 {
00047   myViewPort = ( GLViewer_ViewPort2d* )parent;
00048 
00049   myXPan = 0.0;
00050   myYPan = 0.0;
00051   myZPan = 0.0;
00052   myXScale = 1.0;
00053   myYScale = 1.0;
00054   myZScale = 1.0;
00055   myRotationAngle = 0.0;
00056   myRotationCenterX = 0.0;
00057   myRotationCenterY = 0.0;
00058   myRotationCenterZ = 1.0;
00059   myRotationAnglePrev = 0.0;
00060 
00061   myStart = GL_TRUE;
00062 
00063   isExportMode = false;
00064 
00065   //init();
00066   setMouseTracking( true );
00067 }
00068 
00072 GLViewer_Widget::~GLViewer_Widget()
00073 {
00074 }
00075 
00079 void GLViewer_Widget::getPan( GLfloat& xPan, GLfloat& yPan, GLfloat& zPan )
00080 {
00081   xPan = myXPan;
00082   yPan = myYPan;
00083   zPan = myZPan;
00084 }
00085 
00089 void GLViewer_Widget::setPan( GLfloat xPan, GLfloat yPan, GLfloat zPan )
00090 {
00091   myXPan = xPan;
00092   myYPan = yPan;
00093   myZPan = zPan;
00094 }
00095 
00099 void GLViewer_Widget::getScale( GLfloat& xScale, GLfloat& yScale, GLfloat& zScale )
00100 {
00101   xScale = myXScale;
00102   yScale = myYScale;
00103   zScale = myZScale;
00104 }
00105 
00109 void GLViewer_Widget::setScale( GLfloat xScale, GLfloat yScale, GLfloat zScale )
00110 {
00111   if ( xScale > 0 && yScale > 0 && zScale > 0 )
00112   {
00113     myXScale = xScale;
00114     myYScale = yScale;
00115     myZScale = zScale;
00116   }
00117 }
00118 
00122 void GLViewer_Widget::getRotationStart( GLfloat& rotationStartX,
00123                                         GLfloat& rotationStartY,
00124                                         GLfloat& rotationStartZ )
00125 {
00126     rotationStartX = myRotationStartX;
00127     rotationStartY = myRotationStartY;
00128     rotationStartZ = myRotationStartZ;
00129 }
00130 
00134 void GLViewer_Widget::setRotationStart( GLfloat rotationStartX,
00135                                         GLfloat rotationStartY,
00136                                         GLfloat rotationStartZ )
00137 {
00138     myRotationStartX = rotationStartX;
00139     myRotationStartY = rotationStartY;
00140     myRotationStartZ = rotationStartZ;
00141 }
00142 
00150 void GLViewer_Widget::getRotation( GLfloat& rotationAngle,
00151                                    GLfloat& rotationCenterX,
00152                                    GLfloat& rotationCenterY,
00153                                    GLfloat& rotationCenterZ )
00154 {
00155     rotationAngle = myRotationAngle;
00156     rotationCenterX = myRotationCenterX;
00157     rotationCenterY = myRotationCenterY;
00158     rotationCenterZ = myRotationCenterZ;
00159 }
00160 
00168 void GLViewer_Widget::setRotation( GLfloat rotationAngle,
00169                                    GLfloat rotationCenterX,
00170                                    GLfloat rotationCenterY,
00171                                    GLfloat rotationCenterZ )
00172 {
00173     myRotationAngle = rotationAngle;
00174     myRotationCenterX = rotationCenterX;
00175     myRotationCenterY = rotationCenterY;
00176     myRotationCenterZ = rotationCenterZ;
00177 }
00178 
00179 
00184 void GLViewer_Widget::setBackground( QString filename )
00185 {
00186     
00187     //get image
00188     QImage buf;
00189     if ( !filename.isEmpty() && buf.load( filename ) ) 
00190     {  // Load first image from file
00191         isLoadBackground = true;
00192         myBackgroundFile = filename;
00193 
00194         myIW = buf.width();
00195         myIH = buf.height();
00196 
00197         myBackgroundSize = 64;
00198         while( myBackgroundSize < myIW || myBackgroundSize < myIH)
00199             myBackgroundSize = myBackgroundSize * 2;
00200 
00201         GLubyte* pixels = new GLubyte[myBackgroundSize * myBackgroundSize * 4];
00202 
00203         for( int i = 0; i < myBackgroundSize; i++ )
00204         {            
00205             for( int j = 0; j < myBackgroundSize; j++ )
00206             {
00207                 if( j < myIW && i < myIH )
00208                 {
00209                     pixels[i * myBackgroundSize * 4 + j * 4] = (GLubyte)qRed( buf.pixel(j,myIH - i - 1) );
00210                     pixels[i * myBackgroundSize * 4 + j * 4 + 1]= (GLubyte)qGreen( buf.pixel(j,myIH - i - 1) );
00211                     pixels[i * myBackgroundSize * 4 + j * 4 + 2] = (GLubyte)qBlue( buf.pixel(j,myIH - i - 1) );
00212                 }
00213                 else
00214                 {
00215                     pixels[i * myBackgroundSize * 4 + j * 4] = (GLubyte)0;
00216                     pixels[i * myBackgroundSize * 4 + j * 4 + 1] = (GLubyte)0;
00217                     pixels[i * myBackgroundSize * 4 + j * 4 + 2] = (GLubyte)0;
00218                 }                
00219                 pixels[i * myBackgroundSize* 4 + j * 4 +  3] = (GLubyte)255;
00220             }
00221         }
00222 
00223         //initialize texture
00224         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
00225         glGenTextures(1, &texName);
00226         glBindTexture(GL_TEXTURE_2D, texName);
00227         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
00228         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
00229         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, myBackgroundSize , myBackgroundSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
00230             pixels);
00231 
00232         delete[] pixels;        
00233     }
00234 }
00235 
00241 void GLViewer_Widget::addToolTip( QString theString, QRect theRect )
00242 {
00243     myToolTipRect = theRect;
00244     setToolTip(theString);
00245     //QToolTip::add( this, myToolTipRect, theString );
00246 }
00247 
00251 void GLViewer_Widget::removeToolTip()
00252 {
00253     setToolTip("");
00254     //QToolTip::remove( this, myToolTipRect );
00255 }
00256 
00260 void GLViewer_Widget::initializeGL()
00261 {
00262     setAutoBufferSwap( true );
00263 
00264     glShadeModel(GL_FLAT);
00265     
00266     //get image
00267     QImage buf; 
00268     QString aPicturePath = getenv("GLViewer__Background_Picture");
00269     
00270     if ( !aPicturePath.isEmpty() && buf.load( aPicturePath ) ) 
00271     {  // Load first image from file
00272         isLoadBackground = true;
00273         setBackground( aPicturePath );       
00274         
00275     }
00276     
00277     else
00278         isLoadBackground = false;
00279 }
00280 
00284 void GLViewer_Widget::paintGL()
00285 {
00286     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
00287     
00288     glMatrixMode( GL_MODELVIEW );
00289     glLoadIdentity();    
00290 
00291     glRotatef( myRotationAngle, myRotationCenterX, myRotationCenterY, myRotationCenterZ );
00292     glScalef( myXScale, myYScale, myZScale );
00293     glTranslatef( myXPan, myYPan, myZPan );
00294     
00295     if( isLoadBackground )
00296     {
00297         glEnable(GL_TEXTURE_2D);
00298         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
00299         glBindTexture(GL_TEXTURE_2D, texName);
00300         glBegin(GL_QUADS);
00301 
00302         glTexCoord2f( 0.0, 0.0); glVertex3f( -myIW/2, -myIH/2, 0.0);    
00303         glTexCoord2f( 0.0, (float)myIH/myBackgroundSize ); glVertex3f( -myIW/2, myIH/2, 0.0);
00304         glTexCoord2f( (float)myIW/myBackgroundSize, (float)myIH/myBackgroundSize ); glVertex3f( myIW/2, myIH/2, 0.0);
00305         glTexCoord2f( (float)myIW/myBackgroundSize, 0.0); glVertex3f( myIW/2, -myIH/2, 0.0);
00306         
00307         glEnd();
00308         glFlush();
00309         glDisable(GL_TEXTURE_2D);
00310 
00311         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
00312     }
00313 
00314 
00315     GLViewer_Grid* grid = myViewPort->getGrid();
00316     if( grid )
00317         grid->draw();
00318 
00319     GLViewer_Viewer2d* v = ( GLViewer_Viewer2d* )getViewPort()->getViewFrame()->getViewer();
00320     if( !isExportMode )
00321         v->updateDrawers( GL_FALSE, myXScale, myYScale );
00322     else
00323         v->repaintView( getViewPort()->getViewFrame() );
00324 }
00325 
00331 void GLViewer_Widget::resizeGL( int w, int h )
00332 {
00333 
00334   if( h < 1 ) h = 1;
00335   if( w < 1 ) w = 1;
00336   glViewport( 0, 0, w, h);
00337 
00338   if( myStart )
00339   {
00340     myWidth = w;
00341     myHeight = h;
00342     myStart = GL_FALSE;
00343   }
00344 
00345   myViewPort->initResize( w, h );
00346 
00347   glMatrixMode( GL_PROJECTION );
00348   glLoadIdentity();
00349   GLfloat w_c = w / 2., h_c = h / 2.; 
00350 
00351   gluOrtho2D( -w_c, w_c, -h_c, h_c ); 
00352 
00353   glMatrixMode( GL_MODELVIEW );
00354   glLoadIdentity(); 
00355 }
00356 
00360 void GLViewer_Widget::exportRepaint()
00361 {
00362     isExportMode = true;
00363 
00364     paintGL();
00365 
00366     isExportMode = false;
00367 }
00368 
00372 void GLViewer_Widget::paintEvent( QPaintEvent* e )
00373 {
00374   QApplication::sendEvent( myViewPort, e );
00375 }
00376 
00380 void GLViewer_Widget::mouseMoveEvent( QMouseEvent* e )
00381 {
00382   QApplication::sendEvent( myViewPort, e );
00383 }
00384 
00388 void GLViewer_Widget::mousePressEvent( QMouseEvent* e )
00389 {
00390   QApplication::sendEvent( myViewPort, e );
00391 }
00392 
00396 void GLViewer_Widget::mouseReleaseEvent( QMouseEvent* e )
00397 {
00398   QApplication::sendEvent( myViewPort, e );
00399 }
00400 
00404 void GLViewer_Widget::enterEvent( QEvent* e )
00405 {
00406   updateGL();
00407 }
00408 
00412 void GLViewer_Widget::leaveEvent( QEvent* e )
00413 {
00414   updateGL();
00415 }
00416 
00420 bool GLViewer_Widget::event ( QEvent* e )
00421 {
00422   if (e->type() == QEvent::ToolTip) {
00423     QHelpEvent *helpEvent = static_cast<QHelpEvent *>(e);
00424     if ( myToolTipRect.contains(helpEvent->pos()) )
00425       QToolTip::showText(helpEvent->globalPos(), toolTip());
00426   }
00427   return QGLWidget::event(e);
00428 }
00429 
00434 inline char hex( uchar c )
00435 {
00436   if( c<=9 )
00437     return '0'+c;
00438   else if( c < 16 )
00439     return 'a' + c - 10;
00440 
00441   return ' ';
00442 }
00443 
00461 void AddImagePart( QFile& hFile, QImage& image, int w1, int w2, int h1, int h2, 
00462                    GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aPSCS, 
00463                    double a, double b, double c, double d, double dw, double dh )
00464 {
00465   if( aViewerCS && aPSCS )
00466   {       
00467     double width = w2-w1+1, height = h2-h1+1;
00468     QString aBuffer = "", temp = "%1 %2 8 [ %3 %4 %5 %6 %7 %8 ]\n";
00469     aBuffer += temp.arg( width ).arg( height ).
00470                         arg( a ).arg( b ).arg( c ).arg( d ).
00471                         arg( dw ).arg( dh );
00472     aBuffer += "<\n";   
00473     
00474     char line[81]; line[80] = '\0'; int cur_index = 0;
00475     int full = 0;
00476     for( int i=h2; i>=h1; i-- )
00477     {           
00478       uchar* theCurLine = image.scanLine( i ), cur;
00479       for( int j=w1; j<=w2; j++ )
00480         for( int k=0; k<3; k++ )
00481         {
00482           cur = *(theCurLine+4*j+2-k);
00483           *(line+cur_index) = hex( cur/16 ); //HI
00484           *(line+cur_index+1) = hex( cur%16 ); //LO
00485           full++;
00486           cur_index+=2;
00487           if( cur_index>=80 )
00488           {
00489             aBuffer += line;
00490             aBuffer += "\n";
00491             cur_index = 0;
00492           }
00493         }           
00494     }
00495     
00496     aBuffer += "> false 3 colorimage\n\n";
00497 
00498     hFile.write( aBuffer.toAscii() );
00499   }
00500 }
00501 
00505 void GLViewer_Widget::getBackgroundRectInViewerCS( double& left, double& top, double& right, double& bottom )
00506 {
00507   left = -myIW/2; right = myIW/2; 
00508   top = myIH/2; bottom = -myIH/2;
00509 }
00510 
00517 void GLViewer_Widget::translateBackgroundToPS( QFile& hFile, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aPSCS )
00518 {
00519     QImage buf; 
00520 
00521     if( aViewerCS && aPSCS && isLoadBackground && buf.load( myBackgroundFile ) )
00522     {       
00523         double a, b, c, d, dx, dy; //The preparation of transformation matrix
00524 
00525         double width = buf.width(), height = buf.height();
00526 
00527         double left, top, right, bottom;
00528         getBackgroundRectInViewerCS( left, top, right, bottom );
00529 
00530         double aax = left,  aay = bottom,
00531                bbx = right, bby = bottom,
00532                ccx = left,  ccy = top;             
00533 
00534         aViewerCS->transform( *aPSCS, aax, aay );
00535         aViewerCS->transform( *aPSCS, bbx, bby );
00536         aViewerCS->transform( *aPSCS, ccx, ccy );       
00537 
00538         a = ( bbx - aax ) / width;
00539         b = ( ccx - aax ) / height;
00540         c = ( bby - aay ) / width;
00541         d = ( ccy - aay ) / height;
00542 
00543         //Now we must find invert matrix 
00544         double det = a*d-b*c,
00545                newa = d/det,
00546                newb = -c/det,
00547                newc = -b/det,
00548                newd = a/det;
00549 
00550         a = newa; b = newb; c = newc; d = newd;
00551 
00552         dx = -(a*aax+c*aay);
00553         dy = -(b*aax+d*aay); //according to PS specification of coordinate transformation
00554         
00555         const int max = 133000; //The maximum length of string in PS
00556         int dh = int( floor( double( max ) / ( 3.0*2.0*width ) ) );
00557         for( int k=buf.height()-1; k>=0; k-=dh )
00558             AddImagePart( hFile, buf, 0, buf.width()-1, qMax( k-dh+1, 0 ), k,
00559                           aViewerCS, aPSCS, a, b, c, d, dx, dy-(buf.height()-1-k) );
00560     }
00561 }
00562 
00566 void DecodeScanLine( int width, uchar* dest, int dest_depth, uchar* source, int source_depth )
00567 {
00568 #ifndef WIN32
00569 typedef unsigned int WORD;
00570 #endif
00571 
00572     int aSize = width*dest_depth,
00573         dw = aSize % 8;
00574 
00575     if( dw )
00576         aSize+=dw;
00577 
00578     if( dest_depth==source_depth )
00579         memcpy( dest, source, aSize/8 );
00580     else
00581     {
00582         double r, g, b; WORD color;
00583         for( int i=0; i<width; i++ )
00584         {
00585             color = 0;
00586             switch( source_depth )
00587             {
00588                 case 16:
00589                     memcpy( &color, source + 2*i, 2 );
00590                     b = double( color & 0x001F ) / 31.0;
00591                     g = double( ( color & 0x07E0 ) >> 5 ) / 63.0;
00592                     r = double( ( color & 0xF800 ) >> 11 ) / 31.0;
00593                     break;
00594                 case 24: 
00595                     b = double( *(source + 3*i) ) / 255.0;
00596                     g = double( *(source + 3*i+1) ) / 255.0;
00597                     r = double( *(source + 3*i+2) ) / 255.0;
00598                     break;
00599                 case 32:
00600                     b = double( *(source + 4*i) ) / 255.0;
00601                     g = double( *(source + 4*i+1) ) / 255.0;
00602                     r = double( *(source + 4*i+2) ) / 255.0;
00603                     break;
00604             }
00605             switch( dest_depth )
00606             {
00607                 case 16:
00608                     color = WORD(b*31.0);
00609                     color += (WORD(g*63.0)<<5);
00610                     color += (WORD(r*31.0)<<11);
00611                     memcpy( dest + 2*i, &color, 2 );
00612                     break;
00613                 case 24:
00614                     *( dest + 3*i ) = (uchar)(255*b);
00615                     *( dest + 3*i+1 ) = (uchar)(255*g);
00616                     *( dest + 3*i+2 ) = (uchar)(255*r);
00617                     break;
00618                 case 32:
00619                     *( dest + 4*i ) = (uchar)(255*b);
00620                     *( dest + 4*i+1 ) = (uchar)(255*g);
00621                     *( dest + 4*i+2 ) = (uchar)(255*r);
00622                     *( dest + 4*i+3 ) = 0;
00623                     break;
00624             }
00625         }
00626     }
00627 }
00628 
00629 #ifdef WIN32
00630 
00636 void GLViewer_Widget::translateBackgroundToEMF( HDC dc, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aEMFCS )
00637 {
00638     QImage buf; 
00639 
00640     if( aViewerCS && aEMFCS && isLoadBackground && buf.load( myBackgroundFile ) )
00641     {       
00642         double left, top, right, bottom;
00643         getBackgroundRectInViewerCS( left, top, right, bottom );
00644 
00645         double aRot = aViewerCS->getRotation();
00646 
00647         double lx = left, ly = top;
00648         aViewerCS->transform( *aEMFCS, lx, ly );
00649 
00650         aViewerCS->setRotation( 0.0 ); //we switch off the rotation of CS
00651 
00652         aViewerCS->transform( *aEMFCS, left, top );
00653         aViewerCS->transform( *aEMFCS, right, bottom );
00654         
00655         int w = buf.width(), 
00656             h = buf.height();
00657 
00658         HDC aScrDC = GetDC( 0 );
00659         HDC aCompDC = CreateCompatibleDC( aScrDC );
00660         HBITMAP aBMP = CreateCompatibleBitmap( aScrDC, w, h );
00661 
00662         BITMAP aBitInfo;
00663         GetObject ( aBMP, sizeof(BITMAP), &aBitInfo );
00664         int depth = aBitInfo.bmBitsPixel; //how many bits represent a color of one pixel
00665 
00666         int aLineSize = w*depth;
00667         int dw = aLineSize % 32; //scanline word aligning
00668 
00669         if( dw )
00670             aLineSize += 32-dw;
00671 
00672         aLineSize /= 8;
00673 
00674         BYTE* bits = new BYTE[aLineSize*h];
00675         memset( bits, 0, aLineSize*h );
00676         uchar* aLine = NULL;
00677 
00678         for( int i=0; i<h; i++ )
00679         {
00680             aLine = buf.scanLine( i );
00681             DecodeScanLine( w, bits+aLineSize*i, depth, aLine, buf.depth() );
00682         }
00683 
00684         SetBitmapBits( aBMP, aLineSize*h, bits );
00685 
00686         HGDIOBJ old = SelectObject( aCompDC, aBMP ); 
00687 
00688         XFORM aTrans;
00689         GetWorldTransform( dc, &aTrans );
00690         XFORM aRotTrans = aTrans;
00691         double a = aRotTrans.eM11, 
00692                b = aRotTrans.eM12, 
00693                c = aRotTrans.eM21, 
00694                d = aRotTrans.eM22;
00695 
00696         aRotTrans.eM11 = a*cos( aRot )-b*sin( aRot ); //we multiply the current matrix with the rotation matrix 
00697         aRotTrans.eM12 = a*sin( aRot )+b*cos( aRot );
00698         aRotTrans.eM21 = c*cos( aRot )-d*sin( aRot );
00699         aRotTrans.eM22 = c*sin( aRot )+d*cos( aRot );
00700 
00701         a = aRotTrans.eM11; 
00702         b = aRotTrans.eM12; 
00703         c = aRotTrans.eM21; 
00704         d = aRotTrans.eM22;
00705 
00706         double det = a*d-b*c, //now we find the invert matrix 
00707                newa = d/det,
00708                newb = -c/det,
00709                newc = -b/det,
00710                newd = a/det;
00711 
00712         a = newa; b = newb; c = newc; d = newd;
00713 
00714         aRotTrans.eDx = lx -(a*left+c*top); //we find the dx and dy translating (left,top)->(lx,ly) -                                           
00715         aRotTrans.eDy = ly -(b*left+d*top); //the real image of left-top corner of picture
00716 
00717         SetWorldTransform( dc, &aRotTrans );
00718         int res = StretchBlt( dc, left, top, right-left, bottom-top, aCompDC, 0, 0, w, h, SRCCOPY );
00719         SetWorldTransform( dc, &aTrans );
00720 
00721         SelectObject( aCompDC, old );
00722 
00723         ReleaseDC( 0, aScrDC );
00724         DeleteDC( aCompDC );
00725         DeleteObject( aBMP );
00726         delete[] bits;
00727 
00728         aViewerCS->setRotation( aRot );
00729     }
00730 }
00731 #endif