Salome HOME
b2f3f9ceefffdfcdafb8610d2acd098a994783db
[modules/gui.git] / src / GLViewer / GLViewer_Widget.cxx
1 // File:      GLViewer_Widget.cxx
2 // Created:   November, 2004
3 // Author:    OCC team
4 // Copyright (C) CEA 2004
5
6 /***************************************************************************
7 **  Class:   GLViewer_Widget
8 **  Descr:   OpenGL QWidget for GLViewer
9 **  Module:  GLViewer
10 **  Created: UI team, 27.03.03
11 ****************************************************************************/
12
13 #include "GLViewer_Widget.h"
14
15 #include "GLViewer_ViewPort2d.h"
16 #include "GLViewer_Viewer2d.h"
17 #include "GLViewer_Object.h"
18
19 //#include "QAD_Application.h"
20 //#include <QAD_Desktop.h>
21
22 #include <cmath>
23 using namespace std;
24 //#include <math.h>
25 //#include <stdlib.h>
26 //#include <iostream.h>
27
28 #include <qevent.h>
29 #include <qrect.h>
30
31 #include <qpixmap.h>
32 #include <qimage.h>
33 #include <qapplication.h>
34 #include <qintdict.h>
35 #include <qpaintdevicemetrics.h>
36 #include <qsize.h>
37 #include <qtooltip.h>
38
39 //-----------
40 #include <qfontdialog.h>
41 #include <qfontmetrics.h>
42 #include <qpainter.h>
43 //-----------
44
45 static GLuint texFont;
46 static int fontW;
47 static int fontH;
48
49
50 static void genFont()
51 {
52     bool ok;
53     QFont aFont = QFontDialog::getFont( &ok/*, QAD_Application::getDesktop()*/ );
54     QFontMetrics aFM( aFont );
55     QString aStr;
56     for( int k = 32; k <= 127; k++ )
57     {
58         char aLetter = (char)k;
59         aStr += aLetter;
60     }
61     
62     int pixelsWidth = aFM.width( aStr );
63     int pixelsHigh = aFM.height();
64     int aFontX = 64;
65     int aFontY = 64;
66
67     while( aFontX < pixelsWidth )
68         aFontX = aFontX * 2;
69     while( aFontY < pixelsHigh )
70         aFontY = aFontY * 2;
71
72     QPixmap* aPixmap = new QPixmap( aFontX, aFontY );
73     aPixmap->fill( QColor( 255, 255, 255) );
74     QPainter aPainter( aPixmap );
75     aPainter.setFont( aFont );    
76     aPainter.drawText ( 0, pixelsHigh, aStr );
77     QImage aImage = aPixmap->convertToImage();
78
79     aImage.save( "W:\\Temp\\pic.jpg", "JPEG" );
80
81     char* pixels = new char[aFontX * aFontY * 2];
82
83     for( int i = 0; i < aFontY; i++ )
84     {            
85         for( int j = 0; j < aFontX;  j++ )
86         {
87             if( qRed( aImage.pixel( j, aFontY - i - 1 ) ) == 0 )
88             {
89                 pixels[i * aFontX * 2 + j * 2] = (char) 255;
90                 pixels[i * aFontX * 2 + j * 2 + 1]= (char) 255;
91             }
92             else
93             {
94                 pixels[i * aFontX * 2 + j * 2] = (char) 0;
95                 pixels[i * aFontX * 2 + j * 2 + 1]= (char) 0;
96             }                
97         }
98     }
99
100     glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
101     glGenTextures(1, &texFont);
102     glBindTexture(GL_TEXTURE_2D, texFont);  
103     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
104     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
105     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
106     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
107     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
108     glTexImage2D(GL_TEXTURE_2D, 0, 2, aFontX,
109         aFontY, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, pixels);
110
111     fontW = aFontX;
112     fontH = aFontY;
113
114     delete[] pixels;
115 }
116
117 static void showFont()
118 {
119     glEnable(GL_TEXTURE_2D);
120     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
121     glAlphaFunc(GL_GEQUAL, 0.005F);
122     glEnable(GL_ALPHA_TEST);
123     glColor3f( 1.0, 1.0, 1.0);
124     glBindTexture(GL_TEXTURE_2D, texFont);
125     glBegin(GL_QUADS);
126
127     glTexCoord2f( 0.0, 0.0 ); glVertex3f( -fontW/2, -fontH/2, 1.0 );    
128     glTexCoord2f( 0.0, 1.0 ); glVertex3f( -fontW/2, fontH/2, 1.0 );
129     glTexCoord2f( 1.0, 1.0 ); glVertex3f( fontW/2, fontH/2, 1.0 );
130     glTexCoord2f( 1.0, 0.0 ); glVertex3f( fontW/2, -fontH/2, 1.0 );
131
132     glEnd();
133     glFlush();
134     glDisable(GL_ALPHA_TEST);
135     glDisable(GL_TEXTURE_2D);
136 }
137
138
139 GLViewer_Widget::GLViewer_Widget( QWidget* parent, const char* name ):
140 QGLWidget( parent, 0/*, WRepaintNoErase | WResizeNoErase*/ )
141 {
142   myViewPort = ( GLViewer_ViewPort2d* )parent;
143
144   myXPan = 0.0;
145   myYPan = 0.0;
146   myZPan = 0.0;
147   myXScale = 1.0;
148   myYScale = 1.0;
149   myZScale = 1.0;
150   myRotationAngle = 0.0;
151   myRotationCenterX = 0.0;
152   myRotationCenterY = 0.0;
153   myRotationCenterZ = 1.0;
154   myRotationAnglePrev = 0.0;
155
156   myStart = GL_TRUE;
157
158   isExportMode = false;
159
160   //init();
161   setMouseTracking( true );
162 }
163
164 GLViewer_Widget::~GLViewer_Widget()
165 {
166 }
167
168 void GLViewer_Widget::getPan( GLfloat& xPan, GLfloat& yPan, GLfloat& zPan )
169 {
170   xPan = myXPan;
171   yPan = myYPan;
172   zPan = myZPan;
173 }
174
175 void GLViewer_Widget::setPan( GLfloat xPan, GLfloat yPan, GLfloat zPan )
176 {
177   myXPan = xPan;
178   myYPan = yPan;
179   myZPan = zPan;
180 }
181
182 void GLViewer_Widget::getScale( GLfloat& xScale, GLfloat& yScale, GLfloat& zScale )
183 {
184   xScale = myXScale;
185   yScale = myYScale;
186   zScale = myZScale;
187 }
188
189 void GLViewer_Widget::setScale( GLfloat xScale, GLfloat yScale, GLfloat zScale )
190 {
191   if ( xScale > 0 && yScale > 0 && zScale > 0 )
192   {
193     myXScale = xScale;
194     myYScale = yScale;
195     myZScale = zScale;
196   }
197 }
198
199 void GLViewer_Widget::getRotationStart( GLfloat& rotationStartX, GLfloat& rotationStartY,
200                                      GLfloat& rotationStartZ )
201 {
202     rotationStartX = myRotationStartX;
203     rotationStartY = myRotationStartY;
204     rotationStartZ = myRotationStartZ;
205 }
206
207 void GLViewer_Widget::setRotationStart( GLfloat rotationStartX, GLfloat rotationStartY,
208                                      GLfloat rotationStartZ )
209 {
210     myRotationStartX = rotationStartX;
211     myRotationStartY = rotationStartY;
212     myRotationStartZ = rotationStartZ;
213 }
214
215 void GLViewer_Widget::getRotation( GLfloat& rotationAngle, GLfloat& rotationCenterX,
216                                 GLfloat& rotationCenterY, GLfloat& rotationCenterZ )
217 {
218     rotationAngle = myRotationAngle;
219     rotationCenterX = myRotationCenterX;
220     rotationCenterY = myRotationCenterY;
221     rotationCenterZ = myRotationCenterZ;
222 }
223
224 void GLViewer_Widget::setRotation( GLfloat rotationAngle, GLfloat rotationCenterX,
225                                 GLfloat rotationCenterY, GLfloat rotationCenterZ )
226 {
227     myRotationAngle = rotationAngle;
228     myRotationCenterX = rotationCenterX;
229     myRotationCenterY = rotationCenterY;
230     myRotationCenterZ = rotationCenterZ;
231 }
232
233 void GLViewer_Widget::setBackground( QString filename )
234 {
235     
236     //get image
237     QImage buf;
238     if ( !filename.isEmpty() && buf.load( filename ) ) 
239     {  // Load first image from file
240         isLoadBackground = true;
241         myBackgroundFile = filename;
242
243         myIW = buf.width();
244         myIH = buf.height();
245
246         myBackgroundSize = 64;
247         while( myBackgroundSize < myIW || myBackgroundSize < myIH)
248             myBackgroundSize = myBackgroundSize * 2;
249
250         GLubyte* pixels = new GLubyte[myBackgroundSize * myBackgroundSize * 4];
251
252         for( int i = 0; i < myBackgroundSize; i++ )
253         {            
254             for( int j = 0; j < myBackgroundSize; j++ )
255             {
256                 if( j < myIW && i < myIH )
257                 {
258                     pixels[i * myBackgroundSize * 4 + j * 4] = (GLubyte)qRed( buf.pixel(j,myIH - i - 1) );
259                     pixels[i * myBackgroundSize * 4 + j * 4 + 1]= (GLubyte)qGreen( buf.pixel(j,myIH - i - 1) );
260                     pixels[i * myBackgroundSize * 4 + j * 4 + 2] = (GLubyte)qBlue( buf.pixel(j,myIH - i - 1) );
261                 }
262                 else
263                 {
264                     pixels[i * myBackgroundSize * 4 + j * 4] = (GLubyte)0;
265                     pixels[i * myBackgroundSize * 4 + j * 4 + 1] = (GLubyte)0;
266                     pixels[i * myBackgroundSize * 4 + j * 4 + 2] = (GLubyte)0;
267                 }                
268                 pixels[i * myBackgroundSize* 4 + j * 4 +  3] = (GLubyte)255;
269             }
270         }
271
272         //initialize texture
273         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
274         glGenTextures(1, &texName);
275         glBindTexture(GL_TEXTURE_2D, texName);
276         //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
277         //glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
278         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
279         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
280         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, myBackgroundSize , myBackgroundSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
281             pixels);
282
283         delete[] pixels;        
284     }
285     
286 }
287
288 void GLViewer_Widget::addToolTip( QString theString, QRect theRect )
289 {
290     myToolTipRect = theRect;
291     QToolTip::add( this, myToolTipRect, theString );
292 }
293
294 void GLViewer_Widget::removeToolTip()
295 {
296     QToolTip::remove( this, myToolTipRect );
297 }
298
299 void GLViewer_Widget::initializeGL()
300 {
301     setAutoBufferSwap( true );
302
303 //  cout << "GLViewer_Widget::initializeGL" << endl;
304
305     //glClearColor( 0.0, 0.0, 0.0, 0.0 );
306     //-----------------
307     glShadeModel(GL_FLAT);
308     
309     //get image
310     QImage buf; 
311     QString aPicturePath = getenv("GLViewer__Background_Picture");
312     
313     if ( !aPicturePath.isEmpty() && buf.load( aPicturePath ) ) 
314     {  // Load first image from file
315         isLoadBackground = true;
316         setBackground( aPicturePath );
317        
318         // for test texture font
319         //genFont();
320 /*
321         bool ok;
322         QFont aFont = QFontDialog::getFont( &ok, this );
323         QFontMetrics aFM( aFont );
324         int pixelsWidth = aFM.width( "What's the width of this text?" );
325         int pixelsHigh = aFM.height();
326         int aFontX = 64;
327         int aFontY = 64;
328
329         while( aFontX < pixelsWidth )
330             aFontX = aFontX * 2;
331         while( aFontY < pixelsHigh )
332             aFontY = aFontY * 2;
333
334         myIW = aFontX;
335         myIH = aFontY;
336
337         QPixmap* aPixmap = new QPixmap( aFontX, aFontY );
338         aPixmap->fill( QColor( 255, 255, 255) );
339         QPainter aPainter( aPixmap );
340         aPainter.setFont( aFont );
341         //Painter.setPen( QColor( 0, 0, 0 ) );
342         aPainter.drawText ( 0, pixelsHigh, "A" );
343         QImage aImage = aPixmap->convertToImage();
344
345         aImage.save( "W:\\Temp\\pic.jpg", "JPEG" );
346
347         GLubyte* pixels = new GLubyte[aFontX * aFontY * 2];
348
349         for( int i = 0; i < aFontY; i++ )
350         {            
351             for( int j = 0; j < aFontX;  j++ )
352             {
353                 if( qRed( aImage.pixel( j, myIH - i - 1 ) ) == 0 )
354                 {
355                     pixels[i * aFontX * 2 + j * 2] = (GLubyte) 255;
356                     pixels[i * aFontX * 2 + j * 2 + 1]= (GLubyte) 255;
357                 }
358                 else
359                 {
360                     pixels[i * aFontX * 2 + j * 2] = (GLubyte) 0;
361                     pixels[i * aFontX * 2 + j * 2 + 1]= (GLubyte) 0;
362                 }                
363             }
364         }
365
366
367         glBindTexture(GL_TEXTURE_2D, texName);  
368         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
369         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
370         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
371         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
372         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
373         glTexImage2D(GL_TEXTURE_2D, 0, 2, aFontX,
374             aFontY, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, pixels);
375
376         delete[] pixels;
377 */
378         
379         //tex2 = buf.convertDepth( 32, 0 );
380
381         //tex1 = QGLWidget::convertToGLFormat( tex2 );  // flipped 32bit RGBA
382
383         /*myIW = buf.width();
384         myIH = buf.height();
385
386         myBackgroundSize = 64;
387         while( myBackgroundSize < myIW || myBackgroundSize < myIH)
388             myBackgroundSize = myBackgroundSize * 2;
389
390         GLubyte* pixels = new GLubyte[myBackgroundSize * myBackgroundSize * 4];
391
392         //GLubyte pixels[512][512][3];
393         for( int i = 0; i < myBackgroundSize; i++ )
394         {            
395             for( int j = 0; j < myBackgroundSize; j++ )
396             {
397                 if( j < myIW && i < myIH )
398                 {
399                     pixels[i * myBackgroundSize * 4 + j * 4] = (GLubyte)qRed( buf.pixel(j,myIH - i - 1) );
400                     pixels[i * myBackgroundSize * 4 + j * 4 + 1]= (GLubyte)qGreen( buf.pixel(j,myIH - i - 1) );
401                     pixels[i * myBackgroundSize * 4 + j * 4 + 2] = (GLubyte)qBlue( buf.pixel(j,myIH - i - 1) );
402                 }
403                 else
404                 {
405                     pixels[i * myBackgroundSize * 4 + j * 4] = (GLubyte)0;
406                     pixels[i * myBackgroundSize * 4 + j * 4 + 1] = (GLubyte)0;
407                     pixels[i * myBackgroundSize * 4 + j * 4 + 2] = (GLubyte)0;
408                 }                
409                 pixels[i * myBackgroundSize* 4 + j * 4 +  3] = (GLubyte)255;
410                 //cout << "RED = " << qRed( buf.pixel(i,j) ) << " GREEN  = " << qGreen( buf.pixel(i,j) ) <<
411                 //    " BLUE = " << qBlue( buf.pixel(i,j) ) << endl;
412             }
413         }
414
415         //initialize texture
416         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
417         glGenTextures(1, &texName);
418         glBindTexture(GL_TEXTURE_2D, texName);
419         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
420         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
421         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
422         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
423         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, myBackgroundSize , myBackgroundSize, 0, GL_RGBA, GL_UNSIGNED_BYTE,
424             pixels);
425
426         delete[] pixels;  
427         */
428         
429     }
430     
431     else
432         isLoadBackground = false;
433
434     //GLViewer_TexFont aTexFont;
435     //aTexFont.generateTexture();
436     //aTexFont.drawString( "hello" );
437     //-----------------
438 }
439
440 void GLViewer_Widget::paintGL()
441 {
442 //    cout << "GLViewer_Widget::paintGL" << endl;
443
444     glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
445     
446     glMatrixMode( GL_MODELVIEW );
447     glLoadIdentity();    
448
449     glRotatef( myRotationAngle, myRotationCenterX, myRotationCenterY, myRotationCenterZ );
450     glScalef( myXScale, myYScale, myZScale );
451     glTranslatef( myXPan, myYPan, myZPan );
452     //glRotatef( myRotationAngle, myRotationCenterX, myRotationCenterY, myRotationCenterZ );  
453     
454         if( isLoadBackground )
455     {
456         glEnable(GL_TEXTURE_2D);
457         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL);
458         glBindTexture(GL_TEXTURE_2D, texName);
459         glBegin(GL_QUADS);
460
461         glTexCoord2f( 0.0, 0.0); glVertex3f( -myIW/2, -myIH/2, 0.0);    
462         glTexCoord2f( 0.0, (float)myIH/myBackgroundSize ); glVertex3f( -myIW/2, myIH/2, 0.0);
463         glTexCoord2f( (float)myIW/myBackgroundSize, (float)myIH/myBackgroundSize ); glVertex3f( myIW/2, myIH/2, 0.0);
464         glTexCoord2f( (float)myIW/myBackgroundSize, 0.0); glVertex3f( myIW/2, -myIH/2, 0.0);
465         
466         glEnd();
467         glFlush();
468         glDisable(GL_TEXTURE_2D);
469
470         // for test texture font
471         // showFont();
472         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
473     }
474
475
476     GLViewer_RectangularGrid* grid = myViewPort->getGrid();
477     if( grid )
478         grid->draw();
479     //myViewPort->drawCompass();
480
481     //glEnable( GL_POLYGON_OFFSET_FILL );
482     //glPolygonOffset( 0, 1 );
483
484     GLViewer_Viewer2d* v = ( GLViewer_Viewer2d* )getViewPort()->getViewFrame()->getViewer();
485     if( !isExportMode )
486         v->updateDrawers( GL_FALSE, myXScale, myYScale );
487     else
488         v->repaintView( getViewPort()->getViewFrame() );
489
490     //glDisable( GL_POLYGON_OFFSET_FILL );
491
492 //    GLViewer_TexFont aTexFont;
493 //    aTexFont.generateTexture();
494 //    aTexFont.drawString( "hello" );
495 }
496
497 void GLViewer_Widget::resizeGL( int w, int h )
498 {
499 //  cout << "GLViewer_Widget::resizeGL " << w << " " << h << endl;
500
501   if( h < 1 ) h = 1;
502   if( w < 1 ) w = 1;
503   glViewport( 0, 0, w, h);
504
505   if( myStart )
506   {
507     myWidth = w;
508     myHeight = h;
509     myStart = GL_FALSE;
510   }
511
512   myViewPort->initResize( w, h );
513
514   GLViewer_Viewer2d* v = ( GLViewer_Viewer2d* )getViewPort()->getViewFrame()->getViewer();
515   v->updateDrawers( GL_FALSE, myXScale, myYScale );
516
517   glMatrixMode( GL_PROJECTION );
518   glLoadIdentity();
519   GLfloat w_c = w / 2., h_c = h / 2.; 
520
521   gluOrtho2D( -w_c, w_c, -h_c, h_c ); 
522
523   glMatrixMode( GL_MODELVIEW );
524   glLoadIdentity(); 
525 }
526
527 void GLViewer_Widget::copyBuffers()
528 {
529 //  cout << "GLViewer_Widget::copyBuffers" << endl;
530
531   GLint val[4]; 
532   glGetIntegerv( GL_VIEWPORT, val );
533   glReadBuffer( GL_FRONT );
534   glCopyPixels( val[0], val[1], val[2], val[3], GL_COLOR );
535 }
536
537 void GLViewer_Widget::exportRepaint()
538 {
539     isExportMode = true;
540
541     paintGL();
542
543     isExportMode = false;
544 }
545
546
547 void GLViewer_Widget::paintEvent( QPaintEvent* e )
548 {
549 //  cout << "GLViewer_Widget::paintEvent" << endl;
550   QApplication::sendEvent( myViewPort, e );
551 }
552
553 void GLViewer_Widget::mouseMoveEvent( QMouseEvent* e )
554 {
555 //  cout << "GLViewer_Widget::mouseMoveEvent" << endl;
556   QApplication::sendEvent( myViewPort, e );
557 }
558
559 void GLViewer_Widget::mousePressEvent( QMouseEvent* e )
560 {
561 //  cout << "GLViewer_Widget::mousePressEvent" << endl;
562   QApplication::sendEvent( myViewPort, e );
563 }
564
565 void GLViewer_Widget::mouseReleaseEvent( QMouseEvent* e )
566 {
567 //  cout << "GLViewer_Widget::mouseReleaseEvent" << endl;
568   QApplication::sendEvent( myViewPort, e );
569 }
570
571 void GLViewer_Widget::enterEvent( QEvent* e )
572 {
573 //  cout << "GLViewer_Widget::enterEvent" << endl;
574   updateGL();
575 }
576 void GLViewer_Widget::leaveEvent( QEvent* e )
577 {
578 //  cout << "GLViewer_Widget::leaveEvent" << endl;
579   updateGL();
580 }
581
582 inline char hex( uchar c )
583 {
584     if( c>=0 && c<=9 )
585         return '0'+c;
586     else
587         return 'a'+c-10;
588 }
589
590 void AddImagePart( QFile& hFile, QImage& image, int w1, int w2, int h1, int h2, 
591                    GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aPSCS, 
592                    double a, double b, double c, double d, double dw, double dh )
593 {
594     if( aViewerCS && aPSCS )
595     {       
596         double width = w2-w1+1, height = h2-h1+1;
597         QString aBuffer = "", temp = "%1 %2 8 [ %3 %4 %5 %6 %7 %8 ]\n";
598         aBuffer += temp.arg( width ).arg( height ).
599                         arg( a ).arg( b ).arg( c ).arg( d ).
600                         arg( dw ).arg( dh );
601         aBuffer += "<\n";   
602
603         char line[81]; line[80] = '\0'; int cur_index = 0;
604         int full = 0;
605         for( int i=h2; i>=h1; i-- )
606         {           
607             uchar* theCurLine = image.scanLine( i ), cur;
608             for( int j=w1; j<=w2; j++ )
609                 for( int k=0; k<3; k++ )
610                 {
611                     cur = *(theCurLine+4*j+2-k);
612                     *(line+cur_index) = hex( cur/16 ); //HI
613                     *(line+cur_index+1) = hex( cur%16 ); //LO
614                     full++;
615                     cur_index+=2;
616                     if( cur_index>=80 )
617                     {
618                         aBuffer += line;
619                         aBuffer += "\n";
620                         cur_index = 0;
621                     }
622                 }           
623         }
624
625         aBuffer += "> false 3 colorimage\n\n";
626
627         hFile.writeBlock( aBuffer.ascii(), aBuffer.length() );
628     }
629 }
630
631 void GLViewer_Widget::getBackgroundRectInViewerCS( double& left, double& top, double& right, double& bottom )
632 {
633     left = -myIW/2; right = myIW/2; 
634     top = myIH/2; bottom = -myIH/2;
635 }
636
637 void GLViewer_Widget::translateBackgroundToPS( QFile& hFile, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aPSCS )
638 {
639     QImage buf; 
640
641     if( aViewerCS && aPSCS && isLoadBackground && buf.load( myBackgroundFile ) )
642     {       
643         double a, b, c, d, dx, dy; //The preparation of transformation matrix
644
645         double width = buf.width(), height = buf.height();
646
647         double left, top, right, bottom;
648         getBackgroundRectInViewerCS( left, top, right, bottom );
649
650         double aax = left,  aay = bottom,
651                bbx = right, bby = bottom,
652                ccx = left,  ccy = top;             
653
654         aViewerCS->transform( *aPSCS, aax, aay );
655         aViewerCS->transform( *aPSCS, bbx, bby );
656         aViewerCS->transform( *aPSCS, ccx, ccy );       
657
658         a = ( bbx - aax ) / width;
659         b = ( ccx - aax ) / height;
660         c = ( bby - aay ) / width;
661         d = ( ccy - aay ) / height;
662
663         //Now we must find invert matrix 
664         double det = a*d-b*c,
665                newa = d/det,
666                newb = -c/det,
667                newc = -b/det,
668                newd = a/det;
669
670         a = newa; b = newb; c = newc; d = newd;
671
672         dx = -(a*aax+c*aay);
673         dy = -(b*aax+d*aay); //according to PS specification of coordinate transformation
674         
675         const int max = 133000; //The maximum length of string in PS
676         int dh = int( floor( double( max ) / ( 3.0*2.0*width ) ) );
677         for( int k=buf.height()-1; k>=0; k-=dh )
678             AddImagePart( hFile, buf, 0, buf.width()-1, QMAX( k-dh+1, 0 ), k,
679                           aViewerCS, aPSCS, a, b, c, d, dx, dy-(buf.height()-1-k) );
680     }
681 }
682
683 void DecodeScanLine( int width, uchar* dest, int dest_depth, uchar* source, int source_depth )
684 {
685 #ifndef WIN32
686 typedef unsigned int WORD;
687 #endif
688
689     int aSize = width*dest_depth,
690         dw = aSize % 8;
691
692     if( dw )
693         aSize+=dw;
694
695     if( dest_depth==source_depth )
696         memcpy( dest, source, aSize/8 );
697     else
698     {
699         double r, g, b; WORD color;
700         for( int i=0; i<width; i++ )
701         {
702             color = 0;
703             switch( source_depth )
704             {
705                 case 16:
706                     memcpy( &color, source + 2*i, 2 );
707                     b = double( color & 0x001F ) / 31.0;
708                     g = double( ( color & 0x07E0 ) >> 5 ) / 63.0;
709                     r = double( ( color & 0xF800 ) >> 11 ) / 31.0;
710                     break;
711                 case 24: 
712                     b = double( *(source + 3*i) ) / 255.0;
713                     g = double( *(source + 3*i+1) ) / 255.0;
714                     r = double( *(source + 3*i+2) ) / 255.0;
715                     break;
716                 case 32:
717                     b = double( *(source + 4*i) ) / 255.0;
718                     g = double( *(source + 4*i+1) ) / 255.0;
719                     r = double( *(source + 4*i+2) ) / 255.0;
720                     break;
721             }
722             switch( dest_depth )
723             {
724                 case 16:
725                     color = WORD(b*31.0);
726                     color += (WORD(g*63.0)<<5);
727                     color += (WORD(r*31.0)<<11);
728                     memcpy( dest + 2*i, &color, 2 );
729                     break;
730                 case 24:
731                     *( dest + 3*i ) = 255*b;
732                     *( dest + 3*i+1 ) = 255*g;
733                     *( dest + 3*i+2 ) = 255*r;
734                     break;
735                 case 32:
736                     *( dest + 4*i ) = 255*b;
737                     *( dest + 4*i+1 ) = 255*g;
738                     *( dest + 4*i+2 ) = 255*r;
739                     *( dest + 4*i+3 ) = 0;
740                     break;
741             }
742         }
743     }
744 }
745
746 #ifdef WIN32
747 void GLViewer_Widget::translateBackgroundToEMF( HDC dc, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aEMFCS )
748 {
749     QImage buf; 
750
751     if( aViewerCS && aEMFCS && isLoadBackground && buf.load( myBackgroundFile ) )
752     {       
753         double left, top, right, bottom;
754         getBackgroundRectInViewerCS( left, top, right, bottom );
755
756         double aRot = aViewerCS->getRotation();
757
758         double lx = left, ly = top;
759         aViewerCS->transform( *aEMFCS, lx, ly );
760
761         aViewerCS->setRotation( 0.0 ); //we switch off the rotation of CS
762
763         aViewerCS->transform( *aEMFCS, left, top );
764         aViewerCS->transform( *aEMFCS, right, bottom );
765         
766         int w = buf.width(), 
767             h = buf.height();
768
769         HDC aScrDC = GetDC( 0 );
770         HDC aCompDC = CreateCompatibleDC( aScrDC );
771         HBITMAP aBMP = CreateCompatibleBitmap( aScrDC, w, h );
772
773         BITMAP aBitInfo;
774         GetObject ( aBMP, sizeof(BITMAP), &aBitInfo );
775         int depth = aBitInfo.bmBitsPixel; //how many bits represent a color of one pixel
776
777         int aLineSize = w*depth;
778         int dw = aLineSize % 32; //scanline word aligning
779
780         if( dw )
781             aLineSize += 32-dw;
782
783         aLineSize /= 8;
784
785         BYTE* bits = new BYTE[aLineSize*h];
786         memset( bits, 0, aLineSize*h );
787         uchar* aLine = NULL;
788
789         for( int i=0; i<h; i++ )
790         {
791             aLine = buf.scanLine( i );
792             DecodeScanLine( w, bits+aLineSize*i, depth, aLine, buf.depth() );
793         }
794
795         SetBitmapBits( aBMP, aLineSize*h, bits );
796
797         HGDIOBJ old = SelectObject( aCompDC, aBMP ); 
798
799         XFORM aTrans;
800         GetWorldTransform( dc, &aTrans );
801         XFORM aRotTrans = aTrans;
802         double a = aRotTrans.eM11, 
803                b = aRotTrans.eM12, 
804                c = aRotTrans.eM21, 
805                d = aRotTrans.eM22;
806
807         aRotTrans.eM11 = a*cos( aRot )-b*sin( aRot ); //we multiply the current matrix with the rotation matrix 
808         aRotTrans.eM12 = a*sin( aRot )+b*cos( aRot );
809         aRotTrans.eM21 = c*cos( aRot )-d*sin( aRot );
810         aRotTrans.eM22 = c*sin( aRot )+d*cos( aRot );
811
812         a = aRotTrans.eM11; 
813         b = aRotTrans.eM12; 
814         c = aRotTrans.eM21; 
815         d = aRotTrans.eM22;
816
817         double det = a*d-b*c, //now we find the invert matrix 
818                newa = d/det,
819                newb = -c/det,
820                newc = -b/det,
821                newd = a/det;
822
823         a = newa; b = newb; c = newc; d = newd;
824
825         aRotTrans.eDx = lx -(a*left+c*top); //we find the dx and dy translating (left,top)->(lx,ly) -                                           
826         aRotTrans.eDy = ly -(b*left+d*top); //the real image of left-top corner of picture
827
828         SetWorldTransform( dc, &aRotTrans );
829         int res = StretchBlt( dc, left, top, right-left, bottom-top, aCompDC, 0, 0, w, h, SRCCOPY );
830         SetWorldTransform( dc, &aTrans );
831
832         SelectObject( aCompDC, old );
833
834         ReleaseDC( 0, aScrDC );
835         DeleteDC( aCompDC );
836         DeleteObject( aBMP );
837         delete[] bits;
838
839         aViewerCS->setRotation( aRot );
840     }
841 }
842 #endif