1 // Copyright (C) 2007-2008 CEA/DEN, EDF R&D, OPEN CASCADE
3 // Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
4 // CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
6 // This library is free software; you can redistribute it and/or
7 // modify it under the terms of the GNU Lesser General Public
8 // License as published by the Free Software Foundation; either
9 // version 2.1 of the License.
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 // Lesser General Public License for more details.
16 // You should have received a copy of the GNU Lesser General Public
17 // License along with this library; if not, write to the Free Software
18 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
22 // Author : OPEN CASCADE
23 // File: GLViewer_Widget.cxx
24 // Created: November, 2004
26 #include "GLViewer_Widget.h"
27 #include "GLViewer_ViewPort2d.h"
28 #include "GLViewer_Viewer2d.h"
29 //#include "GLViewer_Compass.h"
30 #include "GLViewer_Grid.h"
31 //#include "GLViewer_Object.h"
32 #include "GLViewer_CoordSystem.h"
33 #include "GLViewer_ViewFrame.h"
39 #include <QPaintEvent>
43 //#include <qpixmap.h>
45 #include <QApplication>
46 //#include <qintdict.h>
47 //#include <qpaintdevicemetrics.h>
53 Parameters using for QOGLWidget as is
55 GLViewer_Widget::GLViewer_Widget( QWidget* parent, const char* name ):
56 QGLWidget( parent, 0/*, WRepaintNoErase | WResizeNoErase*/ )
58 myViewPort = ( GLViewer_ViewPort2d* )parent;
66 myRotationAngle = 0.0;
67 myRotationCenterX = 0.0;
68 myRotationCenterY = 0.0;
69 myRotationCenterZ = 1.0;
70 myRotationAnglePrev = 0.0;
77 setMouseTracking( true );
83 GLViewer_Widget::~GLViewer_Widget()
88 \return offset parameters of Window in OpenGL global scene
90 void GLViewer_Widget::getPan( GLfloat& xPan, GLfloat& yPan, GLfloat& zPan )
98 A function for installing the offset parameters of Window in OpenGL global scene
100 void GLViewer_Widget::setPan( GLfloat xPan, GLfloat yPan, GLfloat zPan )
108 \return scales on OpenGL scene along 3 directions in 2d scene zScale = 1.0
110 void GLViewer_Widget::getScale( GLfloat& xScale, GLfloat& yScale, GLfloat& zScale )
118 A function for installing the scales of OpenGL scene
120 void GLViewer_Widget::setScale( GLfloat xScale, GLfloat yScale, GLfloat zScale )
122 if ( xScale > 0 && yScale > 0 && zScale > 0 )
131 \return start point of curren rotation of Window in OpenGL global scene
133 void GLViewer_Widget::getRotationStart( GLfloat& rotationStartX,
134 GLfloat& rotationStartY,
135 GLfloat& rotationStartZ )
137 rotationStartX = myRotationStartX;
138 rotationStartY = myRotationStartY;
139 rotationStartZ = myRotationStartZ;
143 A function for installing the rotation angle of Window in OpenGL global scene in degree (Only in 2D)
145 void GLViewer_Widget::setRotationStart( GLfloat rotationStartX,
146 GLfloat rotationStartY,
147 GLfloat rotationStartZ )
149 myRotationStartX = rotationStartX;
150 myRotationStartY = rotationStartY;
151 myRotationStartZ = rotationStartZ;
155 \return parameters of rotation
156 \param rotationAngle - angle
157 \param rotationCenterX - center x
158 \param rotationCenterY - center y
159 \param rotationCenterZ - center z
161 void GLViewer_Widget::getRotation( GLfloat& rotationAngle,
162 GLfloat& rotationCenterX,
163 GLfloat& rotationCenterY,
164 GLfloat& rotationCenterZ )
166 rotationAngle = myRotationAngle;
167 rotationCenterX = myRotationCenterX;
168 rotationCenterY = myRotationCenterY;
169 rotationCenterZ = myRotationCenterZ;
173 Sets parameters of rotation
174 \param rotationAngle - angle
175 \param rotationCenterX - center x
176 \param rotationCenterY - center y
177 \param rotationCenterZ - center z
179 void GLViewer_Widget::setRotation( GLfloat rotationAngle,
180 GLfloat rotationCenterX,
181 GLfloat rotationCenterY,
182 GLfloat rotationCenterZ )
184 myRotationAngle = rotationAngle;
185 myRotationCenterX = rotationCenterX;
186 myRotationCenterY = rotationCenterY;
187 myRotationCenterZ = rotationCenterZ;
192 Sets image as background
193 \param filename - name of file
195 void GLViewer_Widget::setBackground( QString filename )
200 if ( !filename.isEmpty() && buf.load( filename ) )
201 { // Load first image from file
202 isLoadBackground = true;
203 myBackgroundFile = filename;
208 myBackgroundSize = 64;
209 while( myBackgroundSize < myIW || myBackgroundSize < myIH)
210 myBackgroundSize = myBackgroundSize * 2;
212 GLubyte* pixels = new GLubyte[myBackgroundSize * myBackgroundSize * 4];
214 for( int i = 0; i < myBackgroundSize; i++ )
216 for( int j = 0; j < myBackgroundSize; j++ )
218 if( j < myIW && i < myIH )
220 pixels[i * myBackgroundSize * 4 + j * 4] = (GLubyte)qRed( buf.pixel(j,myIH - i - 1) );
221 pixels[i * myBackgroundSize * 4 + j * 4 + 1]= (GLubyte)qGreen( buf.pixel(j,myIH - i - 1) );
222 pixels[i * myBackgroundSize * 4 + j * 4 + 2] = (GLubyte)qBlue( buf.pixel(j,myIH - i - 1) );
226 pixels[i * myBackgroundSize * 4 + j * 4] = (GLubyte)0;
227 pixels[i * myBackgroundSize * 4 + j * 4 + 1] = (GLubyte)0;
228 pixels[i * myBackgroundSize * 4 + j * 4 + 2] = (GLubyte)0;
230 pixels[i * myBackgroundSize* 4 + j * 4 + 3] = (GLubyte)255;
235 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
236 glGenTextures(1, &texName);
237 glBindTexture(GL_TEXTURE_2D, texName);
238 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
239 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
240 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, myBackgroundSize , myBackgroundSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
249 \param theString - tooltip text
250 \param theRect - tooltip rectangle
252 void GLViewer_Widget::addToolTip( QString theString, QRect theRect )
254 myToolTipRect = theRect;
255 setToolTip(theString);
256 //QToolTip::add( this, myToolTipRect, theString );
262 void GLViewer_Widget::removeToolTip()
265 //QToolTip::remove( this, myToolTipRect );
269 Initialization (redefined virtual from QGLWidget)
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;
295 void GLViewer_Widget::paintGL()
297 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
299 glMatrixMode( GL_MODELVIEW );
302 glRotatef( myRotationAngle, myRotationCenterX, myRotationCenterY, myRotationCenterZ );
303 glScalef( myXScale, myYScale, myZScale );
304 glTranslatef( myXPan, myYPan, myZPan );
306 if( isLoadBackground )
308 glEnable(GL_TEXTURE_2D);
309 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
310 glBindTexture(GL_TEXTURE_2D, texName);
313 glTexCoord2f( 0.0, 0.0); glVertex3f( -myIW/2, -myIH/2, 0.0);
314 glTexCoord2f( 0.0, (float)myIH/myBackgroundSize ); glVertex3f( -myIW/2, myIH/2, 0.0);
315 glTexCoord2f( (float)myIW/myBackgroundSize, (float)myIH/myBackgroundSize ); glVertex3f( myIW/2, myIH/2, 0.0);
316 glTexCoord2f( (float)myIW/myBackgroundSize, 0.0); glVertex3f( myIW/2, -myIH/2, 0.0);
320 glDisable(GL_TEXTURE_2D);
322 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
326 GLViewer_Grid* grid = myViewPort->getGrid();
330 GLViewer_Viewer2d* v = ( GLViewer_Viewer2d* )getViewPort()->getViewFrame()->getViewer();
332 v->updateDrawers( GL_FALSE, myXScale, myYScale );
334 v->repaintView( getViewPort()->getViewFrame() );
338 Resets OpenGl parameters after resize
340 \param h - new height
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 );
369 Provides repaint in export mode
371 void GLViewer_Widget::exportRepaint()
377 isExportMode = false;
381 Custom paint event handler
383 void GLViewer_Widget::paintEvent( QPaintEvent* e )
385 QApplication::sendEvent( myViewPort, e );
389 Custom mouse move event handler
391 void GLViewer_Widget::mouseMoveEvent( QMouseEvent* e )
393 QApplication::sendEvent( myViewPort, e );
397 Custom mouse press event handler
399 void GLViewer_Widget::mousePressEvent( QMouseEvent* e )
401 QApplication::sendEvent( myViewPort, e );
405 Custom mouse release event handler
407 void GLViewer_Widget::mouseReleaseEvent( QMouseEvent* e )
409 QApplication::sendEvent( myViewPort, e );
413 Custom enter event handler
415 void GLViewer_Widget::enterEvent( QEvent* e )
421 Custom leave event handler
423 void GLViewer_Widget::leaveEvent( QEvent* e )
429 Custom leave event handler
431 bool GLViewer_Widget::event ( QEvent* e )
433 if (e->type() == QEvent::ToolTip) {
434 QHelpEvent *helpEvent = static_cast<QHelpEvent *>(e);
435 if ( myToolTipRect.contains(helpEvent->pos()) )
436 QToolTip::showText(helpEvent->globalPos(), toolTip());
438 return QGLWidget::event(e);
442 \return the hex code of digit < 16
445 inline char hex( uchar c )
456 Translates part of image inside rectangle from w1 to w2 and from h2 to h1 to PS format
457 \param hFile - PostScript file
458 \param image - image to be tarnslated
459 \param w1 - x start position
460 \param w2 - x end position
461 \param h1 - y start position
462 \param h2 - y end position
463 \param aViewerCS - viewer co-ordinate system
464 \param aPSCS - paper co-ordinate system
472 void AddImagePart( QFile& hFile, QImage& image, int w1, int w2, int h1, int h2,
473 GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aPSCS,
474 double a, double b, double c, double d, double dw, double dh )
476 if( aViewerCS && aPSCS )
478 double width = w2-w1+1, height = h2-h1+1;
479 QString aBuffer = "", temp = "%1 %2 8 [ %3 %4 %5 %6 %7 %8 ]\n";
480 aBuffer += temp.arg( width ).arg( height ).
481 arg( a ).arg( b ).arg( c ).arg( d ).
485 char line[81]; line[80] = '\0'; int cur_index = 0;
487 for( int i=h2; i>=h1; i-- )
489 uchar* theCurLine = image.scanLine( i ), cur;
490 for( int j=w1; j<=w2; j++ )
491 for( int k=0; k<3; k++ )
493 cur = *(theCurLine+4*j+2-k);
494 *(line+cur_index) = hex( cur/16 ); //HI
495 *(line+cur_index+1) = hex( cur%16 ); //LO
507 aBuffer += "> false 3 colorimage\n\n";
509 hFile.write( aBuffer.toAscii() );
514 \return background rectangle in viewer CS
516 void GLViewer_Widget::getBackgroundRectInViewerCS( double& left, double& top, double& right, double& bottom )
518 left = -myIW/2; right = myIW/2;
519 top = myIH/2; bottom = -myIH/2;
523 Translates background to PostScript
524 \param hFile - PostScript file
525 \param aViewerCS - viewer co-ordinate system
526 \param aPSCS - paper co-ordinate system
528 void GLViewer_Widget::translateBackgroundToPS( QFile& hFile, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aPSCS )
532 if( aViewerCS && aPSCS && isLoadBackground && buf.load( myBackgroundFile ) )
534 double a, b, c, d, dx, dy; //The preparation of transformation matrix
536 double width = buf.width(), height = buf.height();
538 double left, top, right, bottom;
539 getBackgroundRectInViewerCS( left, top, right, bottom );
541 double aax = left, aay = bottom,
542 bbx = right, bby = bottom,
543 ccx = left, ccy = top;
545 aViewerCS->transform( *aPSCS, aax, aay );
546 aViewerCS->transform( *aPSCS, bbx, bby );
547 aViewerCS->transform( *aPSCS, ccx, ccy );
549 a = ( bbx - aax ) / width;
550 b = ( ccx - aax ) / height;
551 c = ( bby - aay ) / width;
552 d = ( ccy - aay ) / height;
554 //Now we must find invert matrix
555 double det = a*d-b*c,
561 a = newa; b = newb; c = newc; d = newd;
564 dy = -(b*aax+d*aay); //according to PS specification of coordinate transformation
566 const int max = 133000; //The maximum length of string in PS
567 int dh = int( floor( double( max ) / ( 3.0*2.0*width ) ) );
568 for( int k=buf.height()-1; k>=0; k-=dh )
569 AddImagePart( hFile, buf, 0, buf.width()-1, qMax( k-dh+1, 0 ), k,
570 aViewerCS, aPSCS, a, b, c, d, dx, dy-(buf.height()-1-k) );
575 Translates image line with one color depth to line with other depth
577 void DecodeScanLine( int width, uchar* dest, int dest_depth, uchar* source, int source_depth )
580 typedef unsigned int WORD;
583 int aSize = width*dest_depth,
589 if( dest_depth==source_depth )
590 memcpy( dest, source, aSize/8 );
593 double r, g, b; WORD color;
594 for( int i=0; i<width; i++ )
597 switch( source_depth )
600 memcpy( &color, source + 2*i, 2 );
601 b = double( color & 0x001F ) / 31.0;
602 g = double( ( color & 0x07E0 ) >> 5 ) / 63.0;
603 r = double( ( color & 0xF800 ) >> 11 ) / 31.0;
606 b = double( *(source + 3*i) ) / 255.0;
607 g = double( *(source + 3*i+1) ) / 255.0;
608 r = double( *(source + 3*i+2) ) / 255.0;
611 b = double( *(source + 4*i) ) / 255.0;
612 g = double( *(source + 4*i+1) ) / 255.0;
613 r = double( *(source + 4*i+2) ) / 255.0;
619 color = WORD(b*31.0);
620 color += (WORD(g*63.0)<<5);
621 color += (WORD(r*31.0)<<11);
622 memcpy( dest + 2*i, &color, 2 );
625 *( dest + 3*i ) = (uchar)(255*b);
626 *( dest + 3*i+1 ) = (uchar)(255*g);
627 *( dest + 3*i+2 ) = (uchar)(255*r);
630 *( dest + 4*i ) = (uchar)(255*b);
631 *( dest + 4*i+1 ) = (uchar)(255*g);
632 *( dest + 4*i+2 ) = (uchar)(255*r);
633 *( dest + 4*i+3 ) = 0;
642 Translates background to EMF
643 \param dc - descriptor of EMF
644 \param aViewerCS - viewer co-ordinate system
645 \param aPSCS - paper co-ordinate system
647 void GLViewer_Widget::translateBackgroundToEMF( HDC dc, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aEMFCS )
651 if( aViewerCS && aEMFCS && isLoadBackground && buf.load( myBackgroundFile ) )
653 double left, top, right, bottom;
654 getBackgroundRectInViewerCS( left, top, right, bottom );
656 double aRot = aViewerCS->getRotation();
658 double lx = left, ly = top;
659 aViewerCS->transform( *aEMFCS, lx, ly );
661 aViewerCS->setRotation( 0.0 ); //we switch off the rotation of CS
663 aViewerCS->transform( *aEMFCS, left, top );
664 aViewerCS->transform( *aEMFCS, right, bottom );
669 HDC aScrDC = GetDC( 0 );
670 HDC aCompDC = CreateCompatibleDC( aScrDC );
671 HBITMAP aBMP = CreateCompatibleBitmap( aScrDC, w, h );
674 GetObject ( aBMP, sizeof(BITMAP), &aBitInfo );
675 int depth = aBitInfo.bmBitsPixel; //how many bits represent a color of one pixel
677 int aLineSize = w*depth;
678 int dw = aLineSize % 32; //scanline word aligning
685 BYTE* bits = new BYTE[aLineSize*h];
686 memset( bits, 0, aLineSize*h );
689 for( int i=0; i<h; i++ )
691 aLine = buf.scanLine( i );
692 DecodeScanLine( w, bits+aLineSize*i, depth, aLine, buf.depth() );
695 SetBitmapBits( aBMP, aLineSize*h, bits );
697 HGDIOBJ old = SelectObject( aCompDC, aBMP );
700 GetWorldTransform( dc, &aTrans );
701 XFORM aRotTrans = aTrans;
702 double a = aRotTrans.eM11,
707 aRotTrans.eM11 = a*cos( aRot )-b*sin( aRot ); //we multiply the current matrix with the rotation matrix
708 aRotTrans.eM12 = a*sin( aRot )+b*cos( aRot );
709 aRotTrans.eM21 = c*cos( aRot )-d*sin( aRot );
710 aRotTrans.eM22 = c*sin( aRot )+d*cos( aRot );
717 double det = a*d-b*c, //now we find the invert matrix
723 a = newa; b = newb; c = newc; d = newd;
725 aRotTrans.eDx = lx -(a*left+c*top); //we find the dx and dy translating (left,top)->(lx,ly) -
726 aRotTrans.eDy = ly -(b*left+d*top); //the real image of left-top corner of picture
728 SetWorldTransform( dc, &aRotTrans );
729 int res = StretchBlt( dc, left, top, right-left, bottom-top, aCompDC, 0, 0, w, h, SRCCOPY );
730 SetWorldTransform( dc, &aTrans );
732 SelectObject( aCompDC, old );
734 ReleaseDC( 0, aScrDC );
736 DeleteObject( aBMP );
739 aViewerCS->setRotation( aRot );