1 // Copyright (C) 2005 OPEN CASCADE
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org
19 // Author : OPEN CASCADE
22 // File: GLViewer_Widget.cxx
23 // Created: November, 2004
25 //================================================================
26 // Class : GLViewer_Widget
27 // Description : OpenGL QWidget for GLViewer
28 //================================================================
30 #include "GLViewer_Widget.h"
31 #include "GLViewer_ViewPort2d.h"
32 #include "GLViewer_Viewer2d.h"
33 #include "GLViewer_Compass.h"
34 #include "GLViewer_Grid.h"
35 #include "GLViewer_Object.h"
36 #include "GLViewer_CoordSystem.h"
46 #include <qapplication.h>
48 #include <qpaintdevicemetrics.h>
52 //=======================================================================
53 // Function: GLViewer_Widget
55 //=======================================================================
56 GLViewer_Widget::GLViewer_Widget( QWidget* parent, const char* name ):
57 QGLWidget( parent, 0/*, WRepaintNoErase | WResizeNoErase*/ )
59 myViewPort = ( GLViewer_ViewPort2d* )parent;
67 myRotationAngle = 0.0;
68 myRotationCenterX = 0.0;
69 myRotationCenterY = 0.0;
70 myRotationCenterZ = 1.0;
71 myRotationAnglePrev = 0.0;
78 setMouseTracking( true );
81 //=======================================================================
82 // Function: GLViewer_Widget
84 //=======================================================================
85 GLViewer_Widget::~GLViewer_Widget()
89 //=======================================================================
90 // Function: ~GLViewer_Widget
92 //=======================================================================
93 void GLViewer_Widget::getPan( GLfloat& xPan, GLfloat& yPan, GLfloat& zPan )
100 //=======================================================================
103 //=======================================================================
104 void GLViewer_Widget::setPan( GLfloat xPan, GLfloat yPan, GLfloat zPan )
111 //=======================================================================
112 // Function: getScale
114 //=======================================================================
115 void GLViewer_Widget::getScale( GLfloat& xScale, GLfloat& yScale, GLfloat& zScale )
122 //=======================================================================
123 // Function: setScale
125 //=======================================================================
126 void GLViewer_Widget::setScale( GLfloat xScale, GLfloat yScale, GLfloat zScale )
128 if ( xScale > 0 && yScale > 0 && zScale > 0 )
136 //=======================================================================
137 // Function: getRotationStart
139 //=======================================================================
140 void GLViewer_Widget::getRotationStart( GLfloat& rotationStartX,
141 GLfloat& rotationStartY,
142 GLfloat& rotationStartZ )
144 rotationStartX = myRotationStartX;
145 rotationStartY = myRotationStartY;
146 rotationStartZ = myRotationStartZ;
149 //=======================================================================
150 // Function: setRotationStart
152 //=======================================================================
153 void GLViewer_Widget::setRotationStart( GLfloat rotationStartX,
154 GLfloat rotationStartY,
155 GLfloat rotationStartZ )
157 myRotationStartX = rotationStartX;
158 myRotationStartY = rotationStartY;
159 myRotationStartZ = rotationStartZ;
162 //=======================================================================
163 // Function: getRotation
165 //=======================================================================
166 void GLViewer_Widget::getRotation( GLfloat& rotationAngle,
167 GLfloat& rotationCenterX,
168 GLfloat& rotationCenterY,
169 GLfloat& rotationCenterZ )
171 rotationAngle = myRotationAngle;
172 rotationCenterX = myRotationCenterX;
173 rotationCenterY = myRotationCenterY;
174 rotationCenterZ = myRotationCenterZ;
177 //=======================================================================
178 // Function: setRotation
180 //=======================================================================
181 void GLViewer_Widget::setRotation( GLfloat rotationAngle,
182 GLfloat rotationCenterX,
183 GLfloat rotationCenterY,
184 GLfloat rotationCenterZ )
186 myRotationAngle = rotationAngle;
187 myRotationCenterX = rotationCenterX;
188 myRotationCenterY = rotationCenterY;
189 myRotationCenterZ = rotationCenterZ;
192 //=======================================================================
193 // Function: setBackground
195 //=======================================================================
196 void GLViewer_Widget::setBackground( QString filename )
201 if ( !filename.isEmpty() && buf.load( filename ) )
202 { // Load first image from file
203 isLoadBackground = true;
204 myBackgroundFile = filename;
209 myBackgroundSize = 64;
210 while( myBackgroundSize < myIW || myBackgroundSize < myIH)
211 myBackgroundSize = myBackgroundSize * 2;
213 GLubyte* pixels = new GLubyte[myBackgroundSize * myBackgroundSize * 4];
215 for( int i = 0; i < myBackgroundSize; i++ )
217 for( int j = 0; j < myBackgroundSize; j++ )
219 if( j < myIW && i < myIH )
221 pixels[i * myBackgroundSize * 4 + j * 4] = (GLubyte)qRed( buf.pixel(j,myIH - i - 1) );
222 pixels[i * myBackgroundSize * 4 + j * 4 + 1]= (GLubyte)qGreen( buf.pixel(j,myIH - i - 1) );
223 pixels[i * myBackgroundSize * 4 + j * 4 + 2] = (GLubyte)qBlue( buf.pixel(j,myIH - i - 1) );
227 pixels[i * myBackgroundSize * 4 + j * 4] = (GLubyte)0;
228 pixels[i * myBackgroundSize * 4 + j * 4 + 1] = (GLubyte)0;
229 pixels[i * myBackgroundSize * 4 + j * 4 + 2] = (GLubyte)0;
231 pixels[i * myBackgroundSize* 4 + j * 4 + 3] = (GLubyte)255;
236 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
237 glGenTextures(1, &texName);
238 glBindTexture(GL_TEXTURE_2D, texName);
239 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
240 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
241 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, myBackgroundSize , myBackgroundSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
248 //=======================================================================
249 // Function: addToolTip
251 //=======================================================================
252 void GLViewer_Widget::addToolTip( QString theString, QRect theRect )
254 myToolTipRect = theRect;
255 QToolTip::add( this, myToolTipRect, theString );
258 //=======================================================================
259 // Function: removeToolTip
261 //=======================================================================
262 void GLViewer_Widget::removeToolTip()
264 QToolTip::remove( this, myToolTipRect );
267 //=======================================================================
268 // Function: initializeGL
270 //=======================================================================
271 void GLViewer_Widget::initializeGL()
273 setAutoBufferSwap( true );
275 glShadeModel(GL_FLAT);
279 QString aPicturePath = getenv("GLViewer__Background_Picture");
281 if ( !aPicturePath.isEmpty() && buf.load( aPicturePath ) )
282 { // Load first image from file
283 isLoadBackground = true;
284 setBackground( aPicturePath );
289 isLoadBackground = false;
292 //=======================================================================
295 //=======================================================================
296 void GLViewer_Widget::paintGL()
298 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
300 glMatrixMode( GL_MODELVIEW );
303 glRotatef( myRotationAngle, myRotationCenterX, myRotationCenterY, myRotationCenterZ );
304 glScalef( myXScale, myYScale, myZScale );
305 glTranslatef( myXPan, myYPan, myZPan );
307 if( isLoadBackground )
309 glEnable(GL_TEXTURE_2D);
310 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
311 glBindTexture(GL_TEXTURE_2D, texName);
314 glTexCoord2f( 0.0, 0.0); glVertex3f( -myIW/2, -myIH/2, 0.0);
315 glTexCoord2f( 0.0, (float)myIH/myBackgroundSize ); glVertex3f( -myIW/2, myIH/2, 0.0);
316 glTexCoord2f( (float)myIW/myBackgroundSize, (float)myIH/myBackgroundSize ); glVertex3f( myIW/2, myIH/2, 0.0);
317 glTexCoord2f( (float)myIW/myBackgroundSize, 0.0); glVertex3f( myIW/2, -myIH/2, 0.0);
321 glDisable(GL_TEXTURE_2D);
323 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
327 GLViewer_Grid* grid = myViewPort->getGrid();
331 GLViewer_Viewer2d* v = ( GLViewer_Viewer2d* )getViewPort()->getViewFrame()->getViewer();
333 v->updateDrawers( GL_FALSE, myXScale, myYScale );
335 v->repaintView( getViewPort()->getViewFrame() );
338 //=======================================================================
339 // Function: resizeGL
341 //=======================================================================
342 void GLViewer_Widget::resizeGL( int w, int h )
347 glViewport( 0, 0, w, h);
356 myViewPort->initResize( w, h );
358 glMatrixMode( GL_PROJECTION );
360 GLfloat w_c = w / 2., h_c = h / 2.;
362 gluOrtho2D( -w_c, w_c, -h_c, h_c );
364 glMatrixMode( GL_MODELVIEW );
368 //=======================================================================
369 // Function: exportRepaint
371 //=======================================================================
372 void GLViewer_Widget::exportRepaint()
378 isExportMode = false;
381 //=======================================================================
382 // Function: paintEvent
384 //=======================================================================
385 void GLViewer_Widget::paintEvent( QPaintEvent* e )
387 QApplication::sendEvent( myViewPort, e );
390 //=======================================================================
391 // Function: mouseMoveEvent
393 //=======================================================================
394 void GLViewer_Widget::mouseMoveEvent( QMouseEvent* e )
396 QApplication::sendEvent( myViewPort, e );
399 //=======================================================================
400 // Function: mousePressEvent
402 //=======================================================================
403 void GLViewer_Widget::mousePressEvent( QMouseEvent* e )
405 QApplication::sendEvent( myViewPort, e );
408 //=======================================================================
409 // Function: mouseReleaseEvent
411 //=======================================================================
412 void GLViewer_Widget::mouseReleaseEvent( QMouseEvent* e )
414 QApplication::sendEvent( myViewPort, e );
417 //=======================================================================
418 // Function: enterEvent
420 //=======================================================================
421 void GLViewer_Widget::enterEvent( QEvent* e )
426 //=======================================================================
427 // Function: leaveEvent
429 //=======================================================================
430 void GLViewer_Widget::leaveEvent( QEvent* e )
436 //=======================================================================
438 //! Purpose : Returns the hex code of digit < 16
439 //=======================================================================
440 inline char hex( uchar c )
450 //=======================================================================
451 //! Function: AddImagePart
452 //! Purpose : Translates path of image to PS format
453 /*! Image inside rectangle from w1 to w2 and from h2 to h1*/
454 //=======================================================================
455 void AddImagePart( QFile& hFile, QImage& image, int w1, int w2, int h1, int h2,
456 GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aPSCS,
457 double a, double b, double c, double d, double dw, double dh )
459 if( aViewerCS && aPSCS )
461 double width = w2-w1+1, height = h2-h1+1;
462 QString aBuffer = "", temp = "%1 %2 8 [ %3 %4 %5 %6 %7 %8 ]\n";
463 aBuffer += temp.arg( width ).arg( height ).
464 arg( a ).arg( b ).arg( c ).arg( d ).
468 char line[81]; line[80] = '\0'; int cur_index = 0;
470 for( int i=h2; i>=h1; i-- )
472 uchar* theCurLine = image.scanLine( i ), cur;
473 for( int j=w1; j<=w2; j++ )
474 for( int k=0; k<3; k++ )
476 cur = *(theCurLine+4*j+2-k);
477 *(line+cur_index) = hex( cur/16 ); //HI
478 *(line+cur_index+1) = hex( cur%16 ); //LO
490 aBuffer += "> false 3 colorimage\n\n";
492 hFile.writeBlock( aBuffer.ascii(), aBuffer.length() );
496 //=======================================================================
497 // Function: getBackgroundRectInViewerCS
499 //=======================================================================
500 void GLViewer_Widget::getBackgroundRectInViewerCS( double& left, double& top, double& right, double& bottom )
502 left = -myIW/2; right = myIW/2;
503 top = myIH/2; bottom = -myIH/2;
506 //=======================================================================
507 // Function: translateBackgroundToPS
509 //=======================================================================
510 void GLViewer_Widget::translateBackgroundToPS( QFile& hFile, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aPSCS )
514 if( aViewerCS && aPSCS && isLoadBackground && buf.load( myBackgroundFile ) )
516 double a, b, c, d, dx, dy; //The preparation of transformation matrix
518 double width = buf.width(), height = buf.height();
520 double left, top, right, bottom;
521 getBackgroundRectInViewerCS( left, top, right, bottom );
523 double aax = left, aay = bottom,
524 bbx = right, bby = bottom,
525 ccx = left, ccy = top;
527 aViewerCS->transform( *aPSCS, aax, aay );
528 aViewerCS->transform( *aPSCS, bbx, bby );
529 aViewerCS->transform( *aPSCS, ccx, ccy );
531 a = ( bbx - aax ) / width;
532 b = ( ccx - aax ) / height;
533 c = ( bby - aay ) / width;
534 d = ( ccy - aay ) / height;
536 //Now we must find invert matrix
537 double det = a*d-b*c,
543 a = newa; b = newb; c = newc; d = newd;
546 dy = -(b*aax+d*aay); //according to PS specification of coordinate transformation
548 const int max = 133000; //The maximum length of string in PS
549 int dh = int( floor( double( max ) / ( 3.0*2.0*width ) ) );
550 for( int k=buf.height()-1; k>=0; k-=dh )
551 AddImagePart( hFile, buf, 0, buf.width()-1, QMAX( k-dh+1, 0 ), k,
552 aViewerCS, aPSCS, a, b, c, d, dx, dy-(buf.height()-1-k) );
556 //=======================================================================
557 //! Function: DecodeScanLine
558 //! Purpose : Translate image line with one color depth to line wiht other depth
559 //=======================================================================
560 void DecodeScanLine( int width, uchar* dest, int dest_depth, uchar* source, int source_depth )
563 typedef unsigned int WORD;
566 int aSize = width*dest_depth,
572 if( dest_depth==source_depth )
573 memcpy( dest, source, aSize/8 );
576 double r, g, b; WORD color;
577 for( int i=0; i<width; i++ )
580 switch( source_depth )
583 memcpy( &color, source + 2*i, 2 );
584 b = double( color & 0x001F ) / 31.0;
585 g = double( ( color & 0x07E0 ) >> 5 ) / 63.0;
586 r = double( ( color & 0xF800 ) >> 11 ) / 31.0;
589 b = double( *(source + 3*i) ) / 255.0;
590 g = double( *(source + 3*i+1) ) / 255.0;
591 r = double( *(source + 3*i+2) ) / 255.0;
594 b = double( *(source + 4*i) ) / 255.0;
595 g = double( *(source + 4*i+1) ) / 255.0;
596 r = double( *(source + 4*i+2) ) / 255.0;
602 color = WORD(b*31.0);
603 color += (WORD(g*63.0)<<5);
604 color += (WORD(r*31.0)<<11);
605 memcpy( dest + 2*i, &color, 2 );
608 *( dest + 3*i ) = (uchar)(255*b);
609 *( dest + 3*i+1 ) = (uchar)(255*g);
610 *( dest + 3*i+2 ) = (uchar)(255*r);
613 *( dest + 4*i ) = (uchar)(255*b);
614 *( dest + 4*i+1 ) = (uchar)(255*g);
615 *( dest + 4*i+2 ) = (uchar)(255*r);
616 *( dest + 4*i+3 ) = 0;
623 //=======================================================================
624 // Function: translateBackgroundToEMF
626 //=======================================================================
628 void GLViewer_Widget::translateBackgroundToEMF( HDC dc, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aEMFCS )
632 if( aViewerCS && aEMFCS && isLoadBackground && buf.load( myBackgroundFile ) )
634 double left, top, right, bottom;
635 getBackgroundRectInViewerCS( left, top, right, bottom );
637 double aRot = aViewerCS->getRotation();
639 double lx = left, ly = top;
640 aViewerCS->transform( *aEMFCS, lx, ly );
642 aViewerCS->setRotation( 0.0 ); //we switch off the rotation of CS
644 aViewerCS->transform( *aEMFCS, left, top );
645 aViewerCS->transform( *aEMFCS, right, bottom );
650 HDC aScrDC = GetDC( 0 );
651 HDC aCompDC = CreateCompatibleDC( aScrDC );
652 HBITMAP aBMP = CreateCompatibleBitmap( aScrDC, w, h );
655 GetObject ( aBMP, sizeof(BITMAP), &aBitInfo );
656 int depth = aBitInfo.bmBitsPixel; //how many bits represent a color of one pixel
658 int aLineSize = w*depth;
659 int dw = aLineSize % 32; //scanline word aligning
666 BYTE* bits = new BYTE[aLineSize*h];
667 memset( bits, 0, aLineSize*h );
670 for( int i=0; i<h; i++ )
672 aLine = buf.scanLine( i );
673 DecodeScanLine( w, bits+aLineSize*i, depth, aLine, buf.depth() );
676 SetBitmapBits( aBMP, aLineSize*h, bits );
678 HGDIOBJ old = SelectObject( aCompDC, aBMP );
681 GetWorldTransform( dc, &aTrans );
682 XFORM aRotTrans = aTrans;
683 double a = aRotTrans.eM11,
688 aRotTrans.eM11 = a*cos( aRot )-b*sin( aRot ); //we multiply the current matrix with the rotation matrix
689 aRotTrans.eM12 = a*sin( aRot )+b*cos( aRot );
690 aRotTrans.eM21 = c*cos( aRot )-d*sin( aRot );
691 aRotTrans.eM22 = c*sin( aRot )+d*cos( aRot );
698 double det = a*d-b*c, //now we find the invert matrix
704 a = newa; b = newb; c = newc; d = newd;
706 aRotTrans.eDx = lx -(a*left+c*top); //we find the dx and dy translating (left,top)->(lx,ly) -
707 aRotTrans.eDy = ly -(b*left+d*top); //the real image of left-top corner of picture
709 SetWorldTransform( dc, &aRotTrans );
710 int res = StretchBlt( dc, left, top, right-left, bottom-top, aCompDC, 0, 0, w, h, SRCCOPY );
711 SetWorldTransform( dc, &aTrans );
713 SelectObject( aCompDC, old );
715 ReleaseDC( 0, aScrDC );
717 DeleteObject( aBMP );
720 aViewerCS->setRotation( aRot );