1 // Copyright (C) 2007-2023 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, or (at your option) any later version.
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
23 #include "GLViewer_Widget.h"
24 #include "GLViewer_ViewPort2d.h"
25 #include "GLViewer_Viewer2d.h"
26 #include "GLViewer_Grid.h"
27 #include "GLViewer_CoordSystem.h"
28 #include "GLViewer_ViewFrame.h"
33 #include <QPaintEvent>
37 #include <QApplication>
42 Parameters using for QOGLWidget as is
44 GLViewer_Widget::GLViewer_Widget( QWidget* parent, const char* /*name*/ ):
45 QGLWidget( parent, 0/*, WRepaintNoErase | WResizeNoErase*/ )
47 myViewPort = ( GLViewer_ViewPort2d* )parent;
55 myRotationAngle = 0.0;
56 myRotationCenterX = 0.0;
57 myRotationCenterY = 0.0;
58 myRotationCenterZ = 1.0;
59 myRotationAnglePrev = 0.0;
66 setMouseTracking( true );
72 GLViewer_Widget::~GLViewer_Widget()
77 \return offset parameters of Window in OpenGL global scene
79 void GLViewer_Widget::getPan( GLfloat& xPan, GLfloat& yPan, GLfloat& zPan )
87 A function for installing the offset parameters of Window in OpenGL global scene
89 void GLViewer_Widget::setPan( GLfloat xPan, GLfloat yPan, GLfloat zPan )
97 \return scales on OpenGL scene along 3 directions in 2d scene zScale = 1.0
99 void GLViewer_Widget::getScale( GLfloat& xScale, GLfloat& yScale, GLfloat& zScale )
107 A function for installing the scales of OpenGL scene
109 void GLViewer_Widget::setScale( GLfloat xScale, GLfloat yScale, GLfloat zScale )
111 if ( xScale > 0 && yScale > 0 && zScale > 0 )
120 \return start point of curren rotation of Window in OpenGL global scene
122 void GLViewer_Widget::getRotationStart( GLfloat& rotationStartX,
123 GLfloat& rotationStartY,
124 GLfloat& rotationStartZ )
126 rotationStartX = myRotationStartX;
127 rotationStartY = myRotationStartY;
128 rotationStartZ = myRotationStartZ;
132 A function for installing the rotation angle of Window in OpenGL global scene in degree (Only in 2D)
134 void GLViewer_Widget::setRotationStart( GLfloat rotationStartX,
135 GLfloat rotationStartY,
136 GLfloat rotationStartZ )
138 myRotationStartX = rotationStartX;
139 myRotationStartY = rotationStartY;
140 myRotationStartZ = rotationStartZ;
144 \return parameters of rotation
145 \param rotationAngle - angle
146 \param rotationCenterX - center x
147 \param rotationCenterY - center y
148 \param rotationCenterZ - center z
150 void GLViewer_Widget::getRotation( GLfloat& rotationAngle,
151 GLfloat& rotationCenterX,
152 GLfloat& rotationCenterY,
153 GLfloat& rotationCenterZ )
155 rotationAngle = myRotationAngle;
156 rotationCenterX = myRotationCenterX;
157 rotationCenterY = myRotationCenterY;
158 rotationCenterZ = myRotationCenterZ;
162 Sets parameters of rotation
163 \param rotationAngle - angle
164 \param rotationCenterX - center x
165 \param rotationCenterY - center y
166 \param rotationCenterZ - center z
168 void GLViewer_Widget::setRotation( GLfloat rotationAngle,
169 GLfloat rotationCenterX,
170 GLfloat rotationCenterY,
171 GLfloat rotationCenterZ )
173 myRotationAngle = rotationAngle;
174 myRotationCenterX = rotationCenterX;
175 myRotationCenterY = rotationCenterY;
176 myRotationCenterZ = rotationCenterZ;
181 Sets image as background
182 \param filename - name of file
184 void GLViewer_Widget::setBackground( QString filename )
189 if ( !filename.isEmpty() && buf.load( filename ) )
190 { // Load first image from file
191 isLoadBackground = true;
192 myBackgroundFile = filename;
197 myBackgroundSize = 64;
198 while( myBackgroundSize < myIW || myBackgroundSize < myIH)
199 myBackgroundSize = myBackgroundSize * 2;
201 GLubyte* pixels = new GLubyte[myBackgroundSize * myBackgroundSize * 4];
203 for( int i = 0; i < myBackgroundSize; i++ )
205 for( int j = 0; j < myBackgroundSize; j++ )
207 if( j < myIW && i < myIH )
209 pixels[i * myBackgroundSize * 4 + j * 4] = (GLubyte)qRed( buf.pixel(j,myIH - i - 1) );
210 pixels[i * myBackgroundSize * 4 + j * 4 + 1]= (GLubyte)qGreen( buf.pixel(j,myIH - i - 1) );
211 pixels[i * myBackgroundSize * 4 + j * 4 + 2] = (GLubyte)qBlue( buf.pixel(j,myIH - i - 1) );
215 pixels[i * myBackgroundSize * 4 + j * 4] = (GLubyte)0;
216 pixels[i * myBackgroundSize * 4 + j * 4 + 1] = (GLubyte)0;
217 pixels[i * myBackgroundSize * 4 + j * 4 + 2] = (GLubyte)0;
219 pixels[i * myBackgroundSize* 4 + j * 4 + 3] = (GLubyte)255;
224 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
225 glGenTextures(1, &texName);
226 glBindTexture(GL_TEXTURE_2D, texName);
227 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
228 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
229 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, myBackgroundSize , myBackgroundSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
238 \param theString - tooltip text
239 \param theRect - tooltip rectangle
241 void GLViewer_Widget::addToolTip( QString theString, QRect theRect )
243 myToolTipRect = theRect;
244 setToolTip(theString);
245 //QToolTip::add( this, myToolTipRect, theString );
251 void GLViewer_Widget::removeToolTip()
254 //QToolTip::remove( this, myToolTipRect );
258 Initialization (redefined virtual from QGLWidget)
260 void GLViewer_Widget::initializeGL()
262 setAutoBufferSwap( true );
264 glShadeModel(GL_FLAT);
268 QString aPicturePath = Qtx::getenv("GLViewer__Background_Picture");
270 if ( !aPicturePath.isEmpty() && buf.load( aPicturePath ) )
271 { // Load first image from file
272 isLoadBackground = true;
273 setBackground( aPicturePath );
278 isLoadBackground = false;
284 void GLViewer_Widget::paintGL()
286 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
288 glMatrixMode( GL_MODELVIEW );
291 glRotatef( myRotationAngle, myRotationCenterX, myRotationCenterY, myRotationCenterZ );
292 glScalef( myXScale, myYScale, myZScale );
293 glTranslatef( myXPan, myYPan, myZPan );
295 if( isLoadBackground )
297 glEnable(GL_TEXTURE_2D);
298 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
299 glBindTexture(GL_TEXTURE_2D, texName);
302 glTexCoord2f( 0.0, 0.0); glVertex3f( -myIW/2, -myIH/2, 0.0);
303 glTexCoord2f( 0.0, (float)myIH/myBackgroundSize ); glVertex3f( -myIW/2, myIH/2, 0.0);
304 glTexCoord2f( (float)myIW/myBackgroundSize, (float)myIH/myBackgroundSize ); glVertex3f( myIW/2, myIH/2, 0.0);
305 glTexCoord2f( (float)myIW/myBackgroundSize, 0.0); glVertex3f( myIW/2, -myIH/2, 0.0);
309 glDisable(GL_TEXTURE_2D);
311 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
315 GLViewer_Grid* grid = myViewPort->getGrid();
319 GLViewer_Viewer2d* v = ( GLViewer_Viewer2d* )getViewPort()->getViewFrame()->getViewer();
321 v->updateDrawers( GL_FALSE, myXScale, myYScale );
323 v->repaintView( getViewPort()->getViewFrame() );
327 Resets OpenGl parameters after resize
329 \param h - new height
331 void GLViewer_Widget::resizeGL( int w, int h )
336 glViewport( 0, 0, w, h);
345 myViewPort->initResize( w, h );
347 glMatrixMode( GL_PROJECTION );
349 GLfloat w_c = w / 2., h_c = h / 2.;
351 gluOrtho2D( -w_c, w_c, -h_c, h_c );
353 glMatrixMode( GL_MODELVIEW );
358 Provides repaint in export mode
360 void GLViewer_Widget::exportRepaint()
366 isExportMode = false;
370 Custom paint event handler
372 void GLViewer_Widget::paintEvent( QPaintEvent* e )
374 QApplication::sendEvent( myViewPort, e );
378 Custom mouse move event handler
380 void GLViewer_Widget::mouseMoveEvent( QMouseEvent* e )
382 QApplication::sendEvent( myViewPort, e );
386 Custom mouse press event handler
388 void GLViewer_Widget::mousePressEvent( QMouseEvent* e )
390 QApplication::sendEvent( myViewPort, e );
394 Custom mouse release event handler
396 void GLViewer_Widget::mouseReleaseEvent( QMouseEvent* e )
398 QApplication::sendEvent( myViewPort, e );
402 Custom enter event handler
404 void GLViewer_Widget::enterEvent( QEvent* /*e*/ )
410 Custom leave event handler
412 void GLViewer_Widget::leaveEvent( QEvent* /*e*/ )
418 Custom leave event handler
420 bool GLViewer_Widget::event ( QEvent* e )
422 if (e->type() == QEvent::ToolTip) {
423 QHelpEvent *helpEvent = static_cast<QHelpEvent *>(e);
424 if ( myToolTipRect.contains(helpEvent->pos()) )
425 QToolTip::showText(helpEvent->globalPos(), toolTip());
427 return QGLWidget::event(e);
431 \return the hex code of digit < 16
434 inline char hex( uchar c )
445 Translates part of image inside rectangle from w1 to w2 and from h2 to h1 to PS format
446 \param hFile - PostScript file
447 \param image - image to be tarnslated
448 \param w1 - x start position
449 \param w2 - x end position
450 \param h1 - y start position
451 \param h2 - y end position
452 \param aViewerCS - viewer co-ordinate system
453 \param aPSCS - paper co-ordinate system
461 void AddImagePart( QFile& hFile, QImage& image, int w1, int w2, int h1, int h2,
462 GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aPSCS,
463 double a, double b, double c, double d, double dw, double dh )
465 if( aViewerCS && aPSCS )
467 double width = w2-w1+1, height = h2-h1+1;
468 QString aBuffer = "", temp = "%1 %2 8 [ %3 %4 %5 %6 %7 %8 ]\n";
469 aBuffer += temp.arg( width ).arg( height ).
470 arg( a ).arg( b ).arg( c ).arg( d ).
474 char line[81]; line[80] = '\0'; int cur_index = 0;
476 for( int i=h2; i>=h1; i-- )
478 uchar* theCurLine = image.scanLine( i ), cur;
479 for( int j=w1; j<=w2; j++ )
480 for( int k=0; k<3; k++ )
482 cur = *(theCurLine+4*j+2-k);
483 *(line+cur_index) = hex( cur/16 ); //HI
484 *(line+cur_index+1) = hex( cur%16 ); //LO
496 aBuffer += "> false 3 colorimage\n\n";
498 hFile.write( aBuffer.toLatin1() );
503 \return background rectangle in viewer CS
505 void GLViewer_Widget::getBackgroundRectInViewerCS( double& left, double& top, double& right, double& bottom )
507 left = -myIW/2; right = myIW/2;
508 top = myIH/2; bottom = -myIH/2;
512 Translates background to PostScript
513 \param hFile - PostScript file
514 \param aViewerCS - viewer co-ordinate system
515 \param aPSCS - paper co-ordinate system
517 void GLViewer_Widget::translateBackgroundToPS( QFile& hFile, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aPSCS )
521 if( aViewerCS && aPSCS && isLoadBackground && buf.load( myBackgroundFile ) )
523 double a, b, c, d, dx, dy; //The preparation of transformation matrix
525 double width = buf.width(), height = buf.height();
527 double left, top, right, bottom;
528 getBackgroundRectInViewerCS( left, top, right, bottom );
530 double aax = left, aay = bottom,
531 bbx = right, bby = bottom,
532 ccx = left, ccy = top;
534 aViewerCS->transform( *aPSCS, aax, aay );
535 aViewerCS->transform( *aPSCS, bbx, bby );
536 aViewerCS->transform( *aPSCS, ccx, ccy );
538 a = ( bbx - aax ) / width;
539 b = ( ccx - aax ) / height;
540 c = ( bby - aay ) / width;
541 d = ( ccy - aay ) / height;
543 //Now we must find invert matrix
544 double det = a*d-b*c,
550 a = newa; b = newb; c = newc; d = newd;
553 dy = -(b*aax+d*aay); //according to PS specification of coordinate transformation
555 const int max = 133000; //The maximum length of string in PS
556 int dh = int( floor( double( max ) / ( 3.0*2.0*width ) ) );
557 for( int k=buf.height()-1; k>=0; k-=dh )
558 AddImagePart( hFile, buf, 0, buf.width()-1, qMax( k-dh+1, 0 ), k,
559 aViewerCS, aPSCS, a, b, c, d, dx, dy-(buf.height()-1-k) );
564 Translates image line with one color depth to line with other depth
566 void DecodeScanLine( int width, uchar* dest, int dest_depth, uchar* source, int source_depth )
569 typedef unsigned int WORD;
572 int aSize = width*dest_depth,
578 if( dest_depth==source_depth )
579 memcpy( dest, source, aSize/8 );
582 double r=0, g=0, b=0; WORD color;
583 for( int i=0; i<width; i++ )
586 switch( source_depth )
589 memcpy( &color, source + 2*i, 2 );
590 b = double( color & 0x001F ) / 31.0;
591 g = double( ( color & 0x07E0 ) >> 5 ) / 63.0;
592 r = double( ( color & 0xF800 ) >> 11 ) / 31.0;
595 b = double( *(source + 3*i) ) / 255.0;
596 g = double( *(source + 3*i+1) ) / 255.0;
597 r = double( *(source + 3*i+2) ) / 255.0;
600 b = double( *(source + 4*i) ) / 255.0;
601 g = double( *(source + 4*i+1) ) / 255.0;
602 r = double( *(source + 4*i+2) ) / 255.0;
608 color = WORD(b*31.0);
609 color += (WORD(g*63.0)<<5);
610 color += (WORD(r*31.0)<<11);
611 memcpy( dest + 2*i, &color, 2 );
614 *( dest + 3*i ) = (uchar)(255*b);
615 *( dest + 3*i+1 ) = (uchar)(255*g);
616 *( dest + 3*i+2 ) = (uchar)(255*r);
619 *( dest + 4*i ) = (uchar)(255*b);
620 *( dest + 4*i+1 ) = (uchar)(255*g);
621 *( dest + 4*i+2 ) = (uchar)(255*r);
622 *( dest + 4*i+3 ) = 0;
631 Translates background to EMF
632 \param dc - descriptor of EMF
633 \param aViewerCS - viewer co-ordinate system
634 \param aPSCS - paper co-ordinate system
636 void GLViewer_Widget::translateBackgroundToEMF( HDC dc, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aEMFCS )
640 if( aViewerCS && aEMFCS && isLoadBackground && buf.load( myBackgroundFile ) )
642 double left, top, right, bottom;
643 getBackgroundRectInViewerCS( left, top, right, bottom );
645 double aRot = aViewerCS->getRotation();
647 double lx = left, ly = top;
648 aViewerCS->transform( *aEMFCS, lx, ly );
650 aViewerCS->setRotation( 0.0 ); //we switch off the rotation of CS
652 aViewerCS->transform( *aEMFCS, left, top );
653 aViewerCS->transform( *aEMFCS, right, bottom );
658 HDC aScrDC = GetDC( 0 );
659 HDC aCompDC = CreateCompatibleDC( aScrDC );
660 HBITMAP aBMP = CreateCompatibleBitmap( aScrDC, w, h );
663 GetObject ( aBMP, sizeof(BITMAP), &aBitInfo );
664 int depth = aBitInfo.bmBitsPixel; //how many bits represent a color of one pixel
666 int aLineSize = w*depth;
667 int dw = aLineSize % 32; //scanline word aligning
674 BYTE* bits = new BYTE[aLineSize*h];
675 memset( bits, 0, aLineSize*h );
678 for( int i=0; i<h; i++ )
680 aLine = buf.scanLine( i );
681 DecodeScanLine( w, bits+aLineSize*i, depth, aLine, buf.depth() );
684 SetBitmapBits( aBMP, aLineSize*h, bits );
686 HGDIOBJ old = SelectObject( aCompDC, aBMP );
689 GetWorldTransform( dc, &aTrans );
690 XFORM aRotTrans = aTrans;
691 double a = aRotTrans.eM11,
696 aRotTrans.eM11 = a*cos( aRot )-b*sin( aRot ); //we multiply the current matrix with the rotation matrix
697 aRotTrans.eM12 = a*sin( aRot )+b*cos( aRot );
698 aRotTrans.eM21 = c*cos( aRot )-d*sin( aRot );
699 aRotTrans.eM22 = c*sin( aRot )+d*cos( aRot );
706 double det = a*d-b*c, //now we find the invert matrix
712 a = newa; b = newb; c = newc; d = newd;
714 aRotTrans.eDx = lx -(a*left+c*top); //we find the dx and dy translating (left,top)->(lx,ly) -
715 aRotTrans.eDy = ly -(b*left+d*top); //the real image of left-top corner of picture
717 SetWorldTransform( dc, &aRotTrans );
718 int res = StretchBlt( dc, left, top, right-left, bottom-top, aCompDC, 0, 0, w, h, SRCCOPY );
719 SetWorldTransform( dc, &aTrans );
721 SelectObject( aCompDC, old );
723 ReleaseDC( 0, aScrDC );
725 DeleteObject( aBMP );
728 aViewerCS->setRotation( aRot );