1 // File: GLViewer_Widget.cxx
2 // Created: November, 2004
4 // Copyright (C) CEA 2004
6 //================================================================
7 // Class : GLViewer_Widget
8 // Description : OpenGL QWidget for GLViewer
9 //================================================================
11 #include "GLViewer_Widget.h"
12 #include "GLViewer_ViewPort2d.h"
13 #include "GLViewer_Viewer2d.h"
14 #include "GLViewer_Compass.h"
15 #include "GLViewer_Grid.h"
16 #include "GLViewer_Object.h"
17 #include "GLViewer_CoordSystem.h"
27 #include <qapplication.h>
29 #include <qpaintdevicemetrics.h>
33 //=======================================================================
34 // Function: GLViewer_Widget
36 //=======================================================================
37 GLViewer_Widget::GLViewer_Widget( QWidget* parent, const char* name ):
38 QGLWidget( parent, 0/*, WRepaintNoErase | WResizeNoErase*/ )
40 myViewPort = ( GLViewer_ViewPort2d* )parent;
48 myRotationAngle = 0.0;
49 myRotationCenterX = 0.0;
50 myRotationCenterY = 0.0;
51 myRotationCenterZ = 1.0;
52 myRotationAnglePrev = 0.0;
59 setMouseTracking( true );
62 //=======================================================================
63 // Function: GLViewer_Widget
65 //=======================================================================
66 GLViewer_Widget::~GLViewer_Widget()
70 //=======================================================================
71 // Function: ~GLViewer_Widget
73 //=======================================================================
74 void GLViewer_Widget::getPan( GLfloat& xPan, GLfloat& yPan, GLfloat& zPan )
81 //=======================================================================
84 //=======================================================================
85 void GLViewer_Widget::setPan( GLfloat xPan, GLfloat yPan, GLfloat zPan )
92 //=======================================================================
95 //=======================================================================
96 void GLViewer_Widget::getScale( GLfloat& xScale, GLfloat& yScale, GLfloat& zScale )
103 //=======================================================================
104 // Function: setScale
106 //=======================================================================
107 void GLViewer_Widget::setScale( GLfloat xScale, GLfloat yScale, GLfloat zScale )
109 if ( xScale > 0 && yScale > 0 && zScale > 0 )
117 //=======================================================================
118 // Function: getRotationStart
120 //=======================================================================
121 void GLViewer_Widget::getRotationStart( GLfloat& rotationStartX,
122 GLfloat& rotationStartY,
123 GLfloat& rotationStartZ )
125 rotationStartX = myRotationStartX;
126 rotationStartY = myRotationStartY;
127 rotationStartZ = myRotationStartZ;
130 //=======================================================================
131 // Function: setRotationStart
133 //=======================================================================
134 void GLViewer_Widget::setRotationStart( GLfloat rotationStartX,
135 GLfloat rotationStartY,
136 GLfloat rotationStartZ )
138 myRotationStartX = rotationStartX;
139 myRotationStartY = rotationStartY;
140 myRotationStartZ = rotationStartZ;
143 //=======================================================================
144 // Function: getRotation
146 //=======================================================================
147 void GLViewer_Widget::getRotation( GLfloat& rotationAngle,
148 GLfloat& rotationCenterX,
149 GLfloat& rotationCenterY,
150 GLfloat& rotationCenterZ )
152 rotationAngle = myRotationAngle;
153 rotationCenterX = myRotationCenterX;
154 rotationCenterY = myRotationCenterY;
155 rotationCenterZ = myRotationCenterZ;
158 //=======================================================================
159 // Function: setRotation
161 //=======================================================================
162 void GLViewer_Widget::setRotation( GLfloat rotationAngle,
163 GLfloat rotationCenterX,
164 GLfloat rotationCenterY,
165 GLfloat rotationCenterZ )
167 myRotationAngle = rotationAngle;
168 myRotationCenterX = rotationCenterX;
169 myRotationCenterY = rotationCenterY;
170 myRotationCenterZ = rotationCenterZ;
173 //=======================================================================
174 // Function: setBackground
176 //=======================================================================
177 void GLViewer_Widget::setBackground( QString filename )
182 if ( !filename.isEmpty() && buf.load( filename ) )
183 { // Load first image from file
184 isLoadBackground = true;
185 myBackgroundFile = filename;
190 myBackgroundSize = 64;
191 while( myBackgroundSize < myIW || myBackgroundSize < myIH)
192 myBackgroundSize = myBackgroundSize * 2;
194 GLubyte* pixels = new GLubyte[myBackgroundSize * myBackgroundSize * 4];
196 for( int i = 0; i < myBackgroundSize; i++ )
198 for( int j = 0; j < myBackgroundSize; j++ )
200 if( j < myIW && i < myIH )
202 pixels[i * myBackgroundSize * 4 + j * 4] = (GLubyte)qRed( buf.pixel(j,myIH - i - 1) );
203 pixels[i * myBackgroundSize * 4 + j * 4 + 1]= (GLubyte)qGreen( buf.pixel(j,myIH - i - 1) );
204 pixels[i * myBackgroundSize * 4 + j * 4 + 2] = (GLubyte)qBlue( buf.pixel(j,myIH - i - 1) );
208 pixels[i * myBackgroundSize * 4 + j * 4] = (GLubyte)0;
209 pixels[i * myBackgroundSize * 4 + j * 4 + 1] = (GLubyte)0;
210 pixels[i * myBackgroundSize * 4 + j * 4 + 2] = (GLubyte)0;
212 pixels[i * myBackgroundSize* 4 + j * 4 + 3] = (GLubyte)255;
217 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
218 glGenTextures(1, &texName);
219 glBindTexture(GL_TEXTURE_2D, texName);
220 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
221 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
222 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, myBackgroundSize , myBackgroundSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
229 //=======================================================================
230 // Function: addToolTip
232 //=======================================================================
233 void GLViewer_Widget::addToolTip( QString theString, QRect theRect )
235 myToolTipRect = theRect;
236 QToolTip::add( this, myToolTipRect, theString );
239 //=======================================================================
240 // Function: removeToolTip
242 //=======================================================================
243 void GLViewer_Widget::removeToolTip()
245 QToolTip::remove( this, myToolTipRect );
248 //=======================================================================
249 // Function: initializeGL
251 //=======================================================================
252 void GLViewer_Widget::initializeGL()
254 setAutoBufferSwap( true );
256 glShadeModel(GL_FLAT);
260 QString aPicturePath = getenv("GLViewer__Background_Picture");
262 if ( !aPicturePath.isEmpty() && buf.load( aPicturePath ) )
263 { // Load first image from file
264 isLoadBackground = true;
265 setBackground( aPicturePath );
270 isLoadBackground = false;
273 //=======================================================================
276 //=======================================================================
277 void GLViewer_Widget::paintGL()
279 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
281 glMatrixMode( GL_MODELVIEW );
284 glRotatef( myRotationAngle, myRotationCenterX, myRotationCenterY, myRotationCenterZ );
285 glScalef( myXScale, myYScale, myZScale );
286 glTranslatef( myXPan, myYPan, myZPan );
288 if( isLoadBackground )
290 glEnable(GL_TEXTURE_2D);
291 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
292 glBindTexture(GL_TEXTURE_2D, texName);
295 glTexCoord2f( 0.0, 0.0); glVertex3f( -myIW/2, -myIH/2, 0.0);
296 glTexCoord2f( 0.0, (float)myIH/myBackgroundSize ); glVertex3f( -myIW/2, myIH/2, 0.0);
297 glTexCoord2f( (float)myIW/myBackgroundSize, (float)myIH/myBackgroundSize ); glVertex3f( myIW/2, myIH/2, 0.0);
298 glTexCoord2f( (float)myIW/myBackgroundSize, 0.0); glVertex3f( myIW/2, -myIH/2, 0.0);
302 glDisable(GL_TEXTURE_2D);
304 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
308 GLViewer_Grid* grid = myViewPort->getGrid();
312 GLViewer_Viewer2d* v = ( GLViewer_Viewer2d* )getViewPort()->getViewFrame()->getViewer();
314 v->updateDrawers( GL_FALSE, myXScale, myYScale );
316 v->repaintView( getViewPort()->getViewFrame() );
319 //=======================================================================
320 // Function: resizeGL
322 //=======================================================================
323 void GLViewer_Widget::resizeGL( int w, int h )
328 glViewport( 0, 0, w, h);
337 myViewPort->initResize( w, h );
339 glMatrixMode( GL_PROJECTION );
341 GLfloat w_c = w / 2., h_c = h / 2.;
343 gluOrtho2D( -w_c, w_c, -h_c, h_c );
345 glMatrixMode( GL_MODELVIEW );
349 //=======================================================================
350 // Function: exportRepaint
352 //=======================================================================
353 void GLViewer_Widget::exportRepaint()
359 isExportMode = false;
362 //=======================================================================
363 // Function: paintEvent
365 //=======================================================================
366 void GLViewer_Widget::paintEvent( QPaintEvent* e )
368 QApplication::sendEvent( myViewPort, e );
371 //=======================================================================
372 // Function: mouseMoveEvent
374 //=======================================================================
375 void GLViewer_Widget::mouseMoveEvent( QMouseEvent* e )
377 QApplication::sendEvent( myViewPort, e );
380 //=======================================================================
381 // Function: mousePressEvent
383 //=======================================================================
384 void GLViewer_Widget::mousePressEvent( QMouseEvent* e )
386 QApplication::sendEvent( myViewPort, e );
389 //=======================================================================
390 // Function: mouseReleaseEvent
392 //=======================================================================
393 void GLViewer_Widget::mouseReleaseEvent( QMouseEvent* e )
395 QApplication::sendEvent( myViewPort, e );
398 //=======================================================================
399 // Function: enterEvent
401 //=======================================================================
402 void GLViewer_Widget::enterEvent( QEvent* e )
407 //=======================================================================
408 // Function: leaveEvent
410 //=======================================================================
411 void GLViewer_Widget::leaveEvent( QEvent* e )
417 //=======================================================================
419 //! Purpose : Returns the hex code of digit < 16
420 //=======================================================================
421 inline char hex( uchar c )
431 //=======================================================================
432 //! Function: AddImagePart
433 //! Purpose : Translates path of image to PS format
434 /*! Image inside rectangle from w1 to w2 and from h2 to h1*/
435 //=======================================================================
436 void AddImagePart( QFile& hFile, QImage& image, int w1, int w2, int h1, int h2,
437 GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aPSCS,
438 double a, double b, double c, double d, double dw, double dh )
440 if( aViewerCS && aPSCS )
442 double width = w2-w1+1, height = h2-h1+1;
443 QString aBuffer = "", temp = "%1 %2 8 [ %3 %4 %5 %6 %7 %8 ]\n";
444 aBuffer += temp.arg( width ).arg( height ).
445 arg( a ).arg( b ).arg( c ).arg( d ).
449 char line[81]; line[80] = '\0'; int cur_index = 0;
451 for( int i=h2; i>=h1; i-- )
453 uchar* theCurLine = image.scanLine( i ), cur;
454 for( int j=w1; j<=w2; j++ )
455 for( int k=0; k<3; k++ )
457 cur = *(theCurLine+4*j+2-k);
458 *(line+cur_index) = hex( cur/16 ); //HI
459 *(line+cur_index+1) = hex( cur%16 ); //LO
471 aBuffer += "> false 3 colorimage\n\n";
473 hFile.writeBlock( aBuffer.ascii(), aBuffer.length() );
477 //=======================================================================
478 // Function: getBackgroundRectInViewerCS
480 //=======================================================================
481 void GLViewer_Widget::getBackgroundRectInViewerCS( double& left, double& top, double& right, double& bottom )
483 left = -myIW/2; right = myIW/2;
484 top = myIH/2; bottom = -myIH/2;
487 //=======================================================================
488 // Function: translateBackgroundToPS
490 //=======================================================================
491 void GLViewer_Widget::translateBackgroundToPS( QFile& hFile, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aPSCS )
495 if( aViewerCS && aPSCS && isLoadBackground && buf.load( myBackgroundFile ) )
497 double a, b, c, d, dx, dy; //The preparation of transformation matrix
499 double width = buf.width(), height = buf.height();
501 double left, top, right, bottom;
502 getBackgroundRectInViewerCS( left, top, right, bottom );
504 double aax = left, aay = bottom,
505 bbx = right, bby = bottom,
506 ccx = left, ccy = top;
508 aViewerCS->transform( *aPSCS, aax, aay );
509 aViewerCS->transform( *aPSCS, bbx, bby );
510 aViewerCS->transform( *aPSCS, ccx, ccy );
512 a = ( bbx - aax ) / width;
513 b = ( ccx - aax ) / height;
514 c = ( bby - aay ) / width;
515 d = ( ccy - aay ) / height;
517 //Now we must find invert matrix
518 double det = a*d-b*c,
524 a = newa; b = newb; c = newc; d = newd;
527 dy = -(b*aax+d*aay); //according to PS specification of coordinate transformation
529 const int max = 133000; //The maximum length of string in PS
530 int dh = int( floor( double( max ) / ( 3.0*2.0*width ) ) );
531 for( int k=buf.height()-1; k>=0; k-=dh )
532 AddImagePart( hFile, buf, 0, buf.width()-1, QMAX( k-dh+1, 0 ), k,
533 aViewerCS, aPSCS, a, b, c, d, dx, dy-(buf.height()-1-k) );
537 //=======================================================================
538 //! Function: DecodeScanLine
539 //! Purpose : Translate image line with one color depth to line wiht other depth
540 //=======================================================================
541 void DecodeScanLine( int width, uchar* dest, int dest_depth, uchar* source, int source_depth )
544 typedef unsigned int WORD;
547 int aSize = width*dest_depth,
553 if( dest_depth==source_depth )
554 memcpy( dest, source, aSize/8 );
557 double r, g, b; WORD color;
558 for( int i=0; i<width; i++ )
561 switch( source_depth )
564 memcpy( &color, source + 2*i, 2 );
565 b = double( color & 0x001F ) / 31.0;
566 g = double( ( color & 0x07E0 ) >> 5 ) / 63.0;
567 r = double( ( color & 0xF800 ) >> 11 ) / 31.0;
570 b = double( *(source + 3*i) ) / 255.0;
571 g = double( *(source + 3*i+1) ) / 255.0;
572 r = double( *(source + 3*i+2) ) / 255.0;
575 b = double( *(source + 4*i) ) / 255.0;
576 g = double( *(source + 4*i+1) ) / 255.0;
577 r = double( *(source + 4*i+2) ) / 255.0;
583 color = WORD(b*31.0);
584 color += (WORD(g*63.0)<<5);
585 color += (WORD(r*31.0)<<11);
586 memcpy( dest + 2*i, &color, 2 );
589 *( dest + 3*i ) = (uchar)(255*b);
590 *( dest + 3*i+1 ) = (uchar)(255*g);
591 *( dest + 3*i+2 ) = (uchar)(255*r);
594 *( dest + 4*i ) = (uchar)(255*b);
595 *( dest + 4*i+1 ) = (uchar)(255*g);
596 *( dest + 4*i+2 ) = (uchar)(255*r);
597 *( dest + 4*i+3 ) = 0;
604 //=======================================================================
605 // Function: translateBackgroundToEMF
607 //=======================================================================
609 void GLViewer_Widget::translateBackgroundToEMF( HDC dc, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aEMFCS )
613 if( aViewerCS && aEMFCS && isLoadBackground && buf.load( myBackgroundFile ) )
615 double left, top, right, bottom;
616 getBackgroundRectInViewerCS( left, top, right, bottom );
618 double aRot = aViewerCS->getRotation();
620 double lx = left, ly = top;
621 aViewerCS->transform( *aEMFCS, lx, ly );
623 aViewerCS->setRotation( 0.0 ); //we switch off the rotation of CS
625 aViewerCS->transform( *aEMFCS, left, top );
626 aViewerCS->transform( *aEMFCS, right, bottom );
631 HDC aScrDC = GetDC( 0 );
632 HDC aCompDC = CreateCompatibleDC( aScrDC );
633 HBITMAP aBMP = CreateCompatibleBitmap( aScrDC, w, h );
636 GetObject ( aBMP, sizeof(BITMAP), &aBitInfo );
637 int depth = aBitInfo.bmBitsPixel; //how many bits represent a color of one pixel
639 int aLineSize = w*depth;
640 int dw = aLineSize % 32; //scanline word aligning
647 BYTE* bits = new BYTE[aLineSize*h];
648 memset( bits, 0, aLineSize*h );
651 for( int i=0; i<h; i++ )
653 aLine = buf.scanLine( i );
654 DecodeScanLine( w, bits+aLineSize*i, depth, aLine, buf.depth() );
657 SetBitmapBits( aBMP, aLineSize*h, bits );
659 HGDIOBJ old = SelectObject( aCompDC, aBMP );
662 GetWorldTransform( dc, &aTrans );
663 XFORM aRotTrans = aTrans;
664 double a = aRotTrans.eM11,
669 aRotTrans.eM11 = a*cos( aRot )-b*sin( aRot ); //we multiply the current matrix with the rotation matrix
670 aRotTrans.eM12 = a*sin( aRot )+b*cos( aRot );
671 aRotTrans.eM21 = c*cos( aRot )-d*sin( aRot );
672 aRotTrans.eM22 = c*sin( aRot )+d*cos( aRot );
679 double det = a*d-b*c, //now we find the invert matrix
685 a = newa; b = newb; c = newc; d = newd;
687 aRotTrans.eDx = lx -(a*left+c*top); //we find the dx and dy translating (left,top)->(lx,ly) -
688 aRotTrans.eDy = ly -(b*left+d*top); //the real image of left-top corner of picture
690 SetWorldTransform( dc, &aRotTrans );
691 int res = StretchBlt( dc, left, top, right-left, bottom-top, aCompDC, 0, 0, w, h, SRCCOPY );
692 SetWorldTransform( dc, &aTrans );
694 SelectObject( aCompDC, old );
696 ReleaseDC( 0, aScrDC );
698 DeleteObject( aBMP );
701 aViewerCS->setRotation( aRot );