Salome HOME
vro changes to enable antiliasing
[modules/gui.git] / src / GLViewer / GLViewer_Drawer.cxx
1 // File:      GLViewer_Drawer.cxx
2 // Created:   November, 2004
3 // Author:    OCC team
4 // Copyright (C) CEA 2004
5
6 //#include <GLViewerAfx.h>
7 #include "GLViewer_Drawer.h"
8 #include "GLViewer_Object.h"
9 #include "GLViewer_Text.h"
10 #include "GLViewer_ViewFrame.h"
11 #include "GLViewer_ViewPort2d.h"
12
13 #ifndef WIN32
14 #include <GL/glx.h>
15 #endif
16
17 #include <qimage.h>
18 #include <qpainter.h>
19
20 #define TEXT_GAP    5
21
22 GLboolean          TFLoaded = GL_FALSE;
23
24 GLdouble           modelMatrix[16], projMatrix[16];
25 GLint              viewport[4];
26 GLdouble           winx, winy, winz;
27 GLint              status;
28
29 GLViewer_TexFont*  staticGlFont;
30
31 //================================================================
32 // Class       : GLViewer_TexFont
33 // Description : 
34 //================================================================
35 //! code of first font symbol
36 static int FirstSymbolNumber = 32;
37 //! code of last font symbol
38 static int LastSymbolNumber = 127;
39
40 QMap<GLViewer_TexFindId,GLViewer_TexIdStored> GLViewer_TexFont::TexFontBase;
41 QMap<GLViewer_TexFindId,GLuint>               GLViewer_TexFont::BitmapFontCache; 
42
43 //=======================================================================
44 // Function: clearTextBases
45 // Purpose :
46 //=======================================================================
47 void GLViewer_TexFont::clearTextBases()
48 {
49   //cout << "Clear font map" << endl;
50   TexFontBase.clear();
51   BitmapFontCache.clear();
52 }
53
54 //======================================================================
55 // Function: GLViewer_TexFont
56 // Purpose :
57 //=======================================================================
58 GLViewer_TexFont::GLViewer_TexFont()
59 {
60     myQFont = QFont::defaultFont();
61     QFontMetrics aFM( myQFont );        
62     myWidths = new int[LastSymbolNumber - FirstSymbolNumber+1];
63     myPositions = new int[LastSymbolNumber - FirstSymbolNumber+1];
64     mySeparator = 2;
65     for( int k = FirstSymbolNumber, aWidth = 0; k <= LastSymbolNumber; k++ )
66     {
67         myWidths[ k - FirstSymbolNumber ] = aFM.width( k );
68         myPositions[ k - FirstSymbolNumber ] = aWidth;
69         aWidth += myWidths[ k - FirstSymbolNumber ] + 2;//mySeparator;
70     }
71
72     myTexFontWidth = 0;
73     myTexFontHeight = 0;        
74 }
75
76 //======================================================================
77 // Function: GLViewer_TexFont
78 // Purpose :
79 //=======================================================================
80 GLViewer_TexFont::GLViewer_TexFont( QFont* theFont, int theSeparator )
81 {
82     myQFont = *theFont;
83     QFontMetrics aFM( myQFont );        
84     myWidths = new int[LastSymbolNumber - FirstSymbolNumber+1];
85     myPositions = new int[LastSymbolNumber - FirstSymbolNumber+1];
86     mySeparator = theSeparator;
87     for( int k = FirstSymbolNumber, aWidth = 0; k <= LastSymbolNumber; k++ )
88     {
89         myWidths[ k - FirstSymbolNumber ] = aFM.width( k );
90         myPositions[ k - FirstSymbolNumber ] = aWidth;
91         aWidth += myWidths[ k - FirstSymbolNumber ] + 2;//mySeparator;
92     }
93
94     myTexFontWidth = 0;
95     myTexFontHeight = 0;
96     
97 }
98
99 //======================================================================
100 // Function: ~GLViewer_TexFont
101 // Purpose :
102 //=======================================================================
103 GLViewer_TexFont::~GLViewer_TexFont()
104 {
105     delete[] myWidths;
106     delete[] myPositions;
107
108   
109 //======================================================================
110 // Function: generateTexture
111 // Purpose :
112 //=======================================================================
113 void GLViewer_TexFont::generateTexture()
114 {
115     QFontMetrics aFM( myQFont );
116
117     GLViewer_TexFindId aFindFont;
118     aFindFont.myFontString = myQFont.toString();
119     aFindFont.myViewPortId = (int)QGLContext::currentContext();
120         
121     if( TexFontBase.contains( aFindFont ) )
122     {
123         GLViewer_TexIdStored aTexture = TexFontBase[ aFindFont ];
124         myTexFont = aTexture.myTexFontId;
125         myTexFontWidth = aTexture.myTexFontWidth;
126         myTexFontHeight = aTexture.myTexFontHeight;
127     }    
128     else    
129     {
130         QString aStr;
131         int pixelsWidth = 0;
132         int pixelsHight = aFM.height();
133         myTexFontWidth = 64;
134         myTexFontHeight = 64;
135     
136         pixelsWidth = myWidths[LastSymbolNumber - FirstSymbolNumber] + 
137                       myPositions[LastSymbolNumber - FirstSymbolNumber];
138
139         while( myTexFontWidth < pixelsWidth )
140             myTexFontWidth = myTexFontWidth * 2;
141         while( myTexFontHeight < pixelsHight )
142             myTexFontHeight = myTexFontHeight * 2;
143
144         QPixmap aPixmap( myTexFontWidth, myTexFontHeight );
145         aPixmap.fill( QColor( 0, 0, 0) );
146         QPainter aPainter( &aPixmap );
147         aPainter.setFont( myQFont );
148         for( int l = 0/*, gap = 0*/; l < LastSymbolNumber - FirstSymbolNumber; l++  )
149         {
150             QString aLetter;
151             aLetter += (char)(FirstSymbolNumber + l);
152             aPainter.setPen( QColor( 255,255,255) );
153             aPainter.drawText ( myPositions[l], pixelsHight, aLetter );
154         }
155     
156         QImage aImage = aPixmap.convertToImage();
157         char* pixels = new char[myTexFontWidth * myTexFontHeight * 2];
158
159         for( int i = 0; i < myTexFontHeight; i++ )
160         {            
161             for( int j = 0; j < myTexFontWidth;  j++ )
162             {
163                 int aRed = qRed( aImage.pixel( j, myTexFontHeight - i - 1 ) );
164                 int aGreen = qGreen( aImage.pixel( j, myTexFontHeight - i - 1 ) );
165                 int aBlue = qBlue( aImage.pixel( j, myTexFontHeight - i - 1 ) );
166           
167                 if( aRed != 0 || aGreen != 0 || aBlue != 0 )
168                 {
169                     pixels[i * myTexFontWidth * 2 + j * 2] = (GLubyte)( (aRed + aGreen + aBlue)/3 );
170                     pixels[i * myTexFontWidth * 2 + j * 2 + 1]= (GLubyte) 255;
171                 }
172                 else
173                 {
174                     pixels[i * myTexFontWidth * 2 + j * 2] = (GLubyte) 0;
175                     pixels[i * myTexFontWidth * 2 + j * 2 + 1]= (GLubyte) 0;
176                 }                
177             }
178         }
179
180         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
181         glGenTextures(1, &myTexFont);
182         glBindTexture(GL_TEXTURE_2D, myTexFont);  
183         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
184         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
185         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
186         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
187         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
188         glTexImage2D(GL_TEXTURE_2D, 0, 2, myTexFontWidth,
189             myTexFontHeight, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, pixels);
190     
191         delete[] pixels;
192         
193         GLViewer_TexIdStored aTexture;
194         aTexture.myTexFontId = myTexFont;
195         aTexture.myTexFontWidth = myTexFontWidth;
196         aTexture.myTexFontHeight = myTexFontHeight;
197
198         TexFontBase.insert( aFindFont, aTexture );
199     }
200 }
201
202 //======================================================================
203 // Function: drawString
204 // Purpose :
205 //=======================================================================
206 void GLViewer_TexFont::drawString( QString theStr, GLdouble theX , GLdouble theY )
207 {
208     glEnable(GL_TEXTURE_2D);
209     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
210     glPixelTransferi(GL_MAP_COLOR, 0);
211     glAlphaFunc(GL_GEQUAL, 0.5F);
212     glEnable(GL_ALPHA_TEST);
213     glBindTexture(GL_TEXTURE_2D, myTexFont);
214     glBegin(GL_QUADS);
215
216     QFontMetrics aFM( myQFont );
217     int pixelsHeight = aFM.height();
218
219     theY = theY - myTexFontHeight + pixelsHeight;
220
221     for( int i = 0, aGap = 0; i < theStr.length(); i++ )
222     {
223         char aLetter = theStr.data()[i];
224         int aLettIndex = (int)aLetter - FirstSymbolNumber;
225
226         float aLettBegin = (float)myPositions[aLettIndex];
227         float aLettEnd = aLettBegin + myWidths[aLettIndex]-1;
228
229         aLettBegin = aLettBegin / myTexFontWidth;
230         aLettEnd = aLettEnd / myTexFontWidth;
231
232         glTexCoord2f( aLettBegin, 0.0 ); glVertex3f( theX + aGap, theY, 1.0 );
233         glTexCoord2f( aLettBegin, 1.0 ); glVertex3f( theX + aGap, theY + myTexFontHeight, 1.0 );
234         glTexCoord2f( aLettEnd, 1.0 ); glVertex3f( theX + aGap + myWidths[aLettIndex]-1, theY + myTexFontHeight, 1.0 );
235         glTexCoord2f( aLettEnd, 0.0 ); glVertex3f( theX + aGap + myWidths[aLettIndex]-1, theY, 1.0 );
236
237         aGap += myWidths[aLettIndex]-1 + mySeparator;
238     }
239
240     glEnd();
241     glDisable(GL_ALPHA_TEST);
242     glDisable(GL_TEXTURE_2D);
243 }
244
245 //======================================================================
246 // Function: getStringWidth
247 // Purpose :
248 //=======================================================================
249 int GLViewer_TexFont::getStringWidth( QString theStr )
250 {
251     int aWidth = 0;
252     for( int i = 0; i < theStr.length(); i ++ )
253     {
254         char aLetter = theStr.data()[i];
255         int aLettIndex = (int)aLetter - FirstSymbolNumber;
256         aWidth += myWidths[aLettIndex] + mySeparator;
257     }
258
259     return aWidth;
260 }
261
262 //======================================================================
263 // Function: getStringHeight
264 // Purpose :
265 //=======================================================================
266 int GLViewer_TexFont::getStringHeight()
267 {
268     QFontMetrics aFM( myQFont );
269     return aFM.height();
270 }
271
272 //! function for generation list base for bitmap fonts
273 static GLuint displayListBase( QFont* theFont )
274 {
275   GLuint aList = 0;
276   //static QMap<GLViewer_TexFindId, GLuint> fontCache;
277   GLViewer_TexFindId aFindFont;
278   aFindFont.myFontString = theFont->toString();
279
280 #ifdef WIN32
281   HGLRC ctx = ::wglGetCurrentContext();
282   if ( !ctx )
283     return aList;  
284   
285   aFindFont.myViewPortId = (int)ctx;
286
287   if ( GLViewer_TexFont::BitmapFontCache.contains( aFindFont ) )
288     aList = GLViewer_TexFont::BitmapFontCache[aFindFont];
289   else
290   {
291     GLuint listBase = 0;
292     QMap<GLViewer_TexFindId, GLuint>::iterator it = GLViewer_TexFont::BitmapFontCache.begin();
293     for ( ; it != GLViewer_TexFont::BitmapFontCache.end(); ++it )
294     {
295       if ( it.key().myViewPortId == (int)ctx && it.data() > listBase )
296         listBase = it.data();
297     }
298     listBase += 256;
299
300     HDC glHdc = ::wglGetCurrentDC();
301     ::SelectObject( glHdc, theFont->handle() );
302     if ( !::wglUseFontBitmaps( glHdc, 0, 256, listBase ) )
303       listBase = 0;
304     aList = listBase;
305     GLViewer_TexFont::BitmapFontCache[aFindFont] = aList;
306   }
307 #else //X Window
308   Display* aDisp = glXGetCurrentDisplay();
309   if( !aDisp )
310   {
311 #ifdef _DEBUG_
312     printf( "Can't find current dislay\n" );
313 #endif
314     return aList;
315   }
316   
317   GLXContext aCont = glXGetCurrentContext();
318   if( !aCont )
319   {
320 #ifdef _DEBUG_
321     printf( "Can't find current context\n" );
322 #endif
323     return aList;
324   }
325
326   aFindFont.myViewPortId = (int)aCont;
327
328   if ( GLViewer_TexFont::BitmapFontCache.contains( aFindFont ) )
329     aList = GLViewer_TexFont::BitmapFontCache[aFindFont];
330   else
331   {
332     GLuint listBase = 0;
333     QMap<GLViewer_TexFindId, GLuint>::iterator it = GLViewer_TexFont::BitmapFontCache.begin();
334     for ( ; it != GLViewer_TexFont::BitmapFontCache.end(); ++it )
335     {
336       if ( it.key().myViewPortId == (int)aCont && it.data() > listBase )
337         listBase = it.data();
338     }
339     listBase += 256;
340     
341     //glXUseXFont( (Font)(theFont->handle()), 0, 256, listBase );
342     int aFontCont = 0;
343     char** xFontList = XListFonts( aDisp, aFindFont.myFontString.data(), 1, &aFontCont  );
344     if( !theFont->handle() )
345     {       
346 #ifdef _DEBUG_
347       printf( "Can't load font %s. loading default font....\n", aFindFont.myFontString.data() );
348 #endif
349       QString aFontMask ("-*-*-*-r-*-*-");
350       aFontMask += aFindFont.myFontString.section( ',', 1, 1 );
351 #ifdef _DEBUG_
352       printf( "Height of Default font: %s\n", aFindFont.myFontString.section( ',', 1, 1 ).data() );
353 #endif
354       aFontMask += "-*-*-*-m-*-*-*";
355       xFontList = XListFonts( aDisp, aFontMask.data()/*"-*-*-*-r-*-*-12-*-*-*-m-*-*-*"*/, 1, &aFontCont  );
356       if( aFontCont == 0 )
357       {      
358 #ifdef _DEBUG_
359         printf( "Can't load default font\n" );
360 #endif
361         return 0;
362       }
363       glXUseXFont( (Font)(XLoadFont( aDisp,xFontList[0] )), 0, 256, listBase );
364     }
365     else
366       glXUseXFont( (Font)(theFont->handle()), 0, 256, listBase );
367     
368     aList = listBase;
369     GLViewer_TexFont::BitmapFontCache[aFindFont] = aList;
370   }
371
372 #endif
373
374   return aList;
375 }
376
377 /***************************************************************************
378 **  Class:   GLViewer_Drawer
379 **  Descr:   Drawer for GLViewer_Object
380 **  Module:  GLViewer
381 **  Created: UI team, 01.10.01
382 ****************************************************************************/
383 //======================================================================
384 // Function: GLViewer_Drawer
385 // Purpose :
386 //=======================================================================
387 GLViewer_Drawer::GLViewer_Drawer()
388 {
389   myXScale = myYScale = 0.0;
390   myObjects.clear();
391   myTextList = 0/*-1*/;
392   myObjectType = "GLViewer_Object";
393   myPriority = 0;
394 }
395
396 //======================================================================
397 // Function: ~GLViewer_Drawer
398 // Purpose :
399 //=======================================================================
400 GLViewer_Drawer::~GLViewer_Drawer()
401 {
402   myObjects.clear();
403   glDeleteLists( myTextList, 1 );
404 }
405
406 //======================================================================
407 // Function: destroyAllTextures
408 // Purpose :
409 //=======================================================================
410 void GLViewer_Drawer::destroyAllTextures()
411 {
412     QMap<GLViewer_TexFindId,GLViewer_TexIdStored>::Iterator anIt= GLViewer_TexFont::TexFontBase.begin();
413     QMap<GLViewer_TexFindId,GLViewer_TexIdStored>::Iterator anEndIt= GLViewer_TexFont::TexFontBase.end();
414
415     for( ; anIt != anEndIt; anIt++ )
416         glDeleteTextures( 1, &(anIt.data().myTexFontId) );
417 }
418
419 //=======================================================================
420 // Function: setAntialiasing
421 // Purpose : The function enables and disables antialiasing in Open GL (for points, lines and polygons).
422 //=======================================================================
423 void GLViewer_Drawer::setAntialiasing(const bool on)
424 {
425         if (on)
426         {
427     glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
428     glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
429
430                 glEnable(GL_POINT_SMOOTH);
431                 glEnable(GL_LINE_SMOOTH);
432                 glEnable(GL_POLYGON_SMOOTH);
433                 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 
434                 glEnable (GL_BLEND);
435         }
436         else
437         {
438                 glDisable(GL_POINT_SMOOTH);
439                 glDisable(GL_LINE_SMOOTH);
440                 glDisable(GL_POLYGON_SMOOTH);
441                 glBlendFunc (GL_ONE, GL_ZERO);
442                 glDisable (GL_BLEND);
443         }
444 }
445
446 //======================================================================
447 // Function: loadTexture
448 // Purpose :
449 //=======================================================================
450 GLuint GLViewer_Drawer::loadTexture( const QString& fileName )
451 {
452     QImage buf;
453     if ( fileName.isEmpty() || !buf.load( fileName ) )
454         return 0;
455
456     int w = buf.width();
457     int h = buf.height();
458
459     int size = 16;
460     while( size < w || size < h )
461         size = size * 2;
462
463     GLuint texture;
464     GLubyte* pixels = new GLubyte[ size * size * 4 ];
465
466     for( int i = 0; i < size; i++ )
467     {            
468         for( int j = 0; j < size; j++ )
469         {
470             GLubyte r, g, b, a;
471             if( j < w && i < h )
472             {
473                 QRgb pixel = buf.pixel( j, h - i - 1 );
474                 r = (GLubyte)qRed( pixel );
475                 g = (GLubyte)qGreen( pixel );
476                 b = (GLubyte)qBlue( pixel );
477                 a = (GLubyte)qAlpha( pixel );
478             }
479             else
480             {
481                 r = (GLubyte)255;
482                 g = (GLubyte)255;
483                 b = (GLubyte)255;
484                 a = (GLubyte)255;
485             }
486
487             int index = 4 * ( i * size + j );
488             pixels[ index ] = r;
489             pixels[ index + 1 ] = g;
490             pixels[ index + 2 ] = b;
491             pixels[ index + 3 ] = a;
492         }
493     }
494
495     //initialize texture
496     glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
497     glGenTextures( 1, &texture );
498     glBindTexture( GL_TEXTURE_2D, texture );
499     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
500     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
501     glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, size, size, 0,
502                   GL_RGBA, GL_UNSIGNED_BYTE, pixels );
503
504     delete[] pixels;
505
506     return texture;
507 }
508
509 //======================================================================
510 // Function: drawTexture
511 // Purpose :
512 //=======================================================================
513 void GLViewer_Drawer::drawTexture( GLuint texture, GLint size, GLfloat x, GLfloat y )
514 {
515     if( !texture )
516         return;
517
518     glColor4f( 1.0, 1.0, 1.0, 1.0 );
519
520     glEnable( GL_TEXTURE_2D );
521     glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
522     glAlphaFunc( GL_GREATER, 0.95F );
523     glEnable( GL_ALPHA_TEST );
524     
525     glBindTexture( GL_TEXTURE_2D, texture );
526     glBegin( GL_QUADS );
527
528     glTexCoord2f( 0.0, 0.0 );
529     glVertex3f( x-size/2., y-size/2., 0.0 );
530
531     glTexCoord2f( 0.0, 1.0 );
532     glVertex3f( x-size/2., y+size/2., 0.0 );
533
534     glTexCoord2f( 1.0, 1.0 );
535     glVertex3f( x+size/2., y+size/2., 0.0 );
536
537     glTexCoord2f( 1.0, 0.0 );
538     glVertex3f( x+size/2., y-size/2., 0.0 );
539     
540     glEnd();
541     glFlush();
542
543     glDisable( GL_ALPHA_TEST );
544     glDisable( GL_TEXTURE_2D );
545 }
546
547 //======================================================================
548 // Function: drawText
549 // Purpose :
550 //=======================================================================
551 void GLViewer_Drawer::drawText( const QString& text, GLfloat xPos, GLfloat yPos,
552                                 const QColor& color, QFont* theFont, int theSeparator, DisplayTextFormat theFormat )
553 {
554   if( theFormat == DTF_TEXTURE )
555   {
556     GLViewer_TexFont aTexFont( theFont, theSeparator );
557     aTexFont.generateTexture();
558
559     glGetIntegerv (GL_VIEWPORT, viewport);
560     glGetDoublev (GL_MODELVIEW_MATRIX, modelMatrix);
561     glGetDoublev (GL_PROJECTION_MATRIX, projMatrix);
562     status = gluProject (xPos, yPos, 0, modelMatrix, projMatrix, viewport, &winx, &winy, &winz);
563
564     glPushAttrib( GL_TRANSFORM_BIT | GL_VIEWPORT_BIT | GL_LIST_BIT );
565     glMatrixMode(GL_PROJECTION);
566     glPushMatrix();
567     glLoadIdentity();
568     glOrtho(0,viewport[2],0,viewport[3],-100,100);
569     glMatrixMode(GL_MODELVIEW);
570     glPushMatrix();
571     glLoadIdentity();
572
573     glColor3f( ( GLfloat )color.red() / 255, 
574                ( GLfloat )color.green() / 255, 
575                ( GLfloat )color.blue() / 255 );
576
577     aTexFont.drawString( text, winx, winy );
578
579     glPopMatrix();
580     glMatrixMode(GL_PROJECTION);
581     glPopMatrix();
582     glPopAttrib();
583   }
584   else if( theFormat == DTF_BITMAP )
585   {
586     glColor3f( ( GLfloat )color.red() / 255, 
587                ( GLfloat )color.green() / 255, 
588                ( GLfloat )color.blue() / 255 );
589     glRasterPos2f( xPos, yPos );
590     glListBase( displayListBase( theFont ) );
591     glCallLists( text.length(), GL_UNSIGNED_BYTE, text.local8Bit().data() );
592   }
593 }
594
595 //======================================================================
596 // Function: drawText
597 // Purpose :
598 //=======================================================================
599 void GLViewer_Drawer::drawText( GLViewer_Object* theObject )
600 {
601   if( !theObject )
602     return;
603
604   GLViewer_Text* aText = theObject->getGLText();
605   if( !aText )
606     return;
607
608   GLfloat aPosX, aPosY;
609   aText->getPosition( aPosX, aPosY );
610   // get temporary copy of font
611   QFont aTmpVarFont = aText->getFont();
612   drawText( aText->getText(), aPosX, aPosY, aText->getColor(), &aTmpVarFont, aText->getSeparator(), aText->getDisplayTextFormat() );
613 }
614
615 //======================================================================
616 // Function: drawGLText
617 // Purpose :
618 //=======================================================================
619 void GLViewer_Drawer::drawGLText( QString text, float x, float y,
620                                   int hPosition, int vPosition, QColor color, bool smallFont )
621 {
622   QFont aFont( "Arial", 10, QFont::Bold );
623   if( smallFont )
624     aFont.setPointSize( 8 );
625
626   QFontMetrics aFontMetrics( aFont );
627   float width = aFontMetrics.width( text ) / myXScale;
628   float height = aFontMetrics.height() / myXScale;
629   float gap = 5 / myXScale;
630
631   switch( hPosition )
632   {
633       case GLText_Left   : x -= ( gap + width ); break;
634       case GLText_Center : x -= width / 2; break;
635       case GLText_Right  : x += gap; break;
636       default : break;
637   }
638
639   switch( vPosition )
640   {
641       case GLText_Top    : y += height * 0.5; break;
642       case GLText_Center : y -= height * 0.5; break;
643       case GLText_Bottom : y -= height * 1.5; break;
644       default : break;
645   }
646
647   drawText( text, x, y, color, &aFont, 2, DTF_BITMAP ); // DTF_BITMAP or DTF_TEXTURE
648 }
649
650 //======================================================================
651 // Function: drawRectangle
652 // Purpose :
653 //=======================================================================
654 void GLViewer_Drawer::drawRectangle( GLViewer_Rect* rect, QColor color )
655 {
656   if( !rect )
657     return;
658
659   float x1 = rect->left();
660   float x2 = rect->right();
661   float y1 = rect->bottom();
662   float y2 = rect->top();
663   
664   glColor3f( ( GLfloat )color.red() / 255,
665     ( GLfloat )color.green() / 255,
666     ( GLfloat )color.blue() / 255 );
667   glLineWidth( 1.0 );
668   
669   glBegin( GL_LINE_LOOP );
670   glVertex2f( x1, y1 );
671   glVertex2f( x1, y2 );
672   glVertex2f( x2, y2 );
673   glVertex2f( x2, y1 );
674   glEnd();
675 }
676
677 //======================================================================
678 // Function: translateToHPGL
679 // Purpose :
680 //=======================================================================
681 bool GLViewer_Drawer::translateToHPGL( QFile& hFile, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aHPGLCS )
682 {
683     bool result = true;
684     for( int i=0, n=myObjects.count(); i<n; i++ ) 
685         result &= myObjects[i]->translateToHPGL( hFile, aViewerCS, aHPGLCS );
686     return result;
687 }
688
689 //======================================================================
690 // Function: translateToPS
691 // Purpose :
692 //=======================================================================
693 bool GLViewer_Drawer::translateToPS( QFile& hFile, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aPSCS )
694 {
695     bool result = true;
696     for( int i=0, n=myObjects.count(); i<n; i++ ) 
697         result &= myObjects[i]->translateToPS( hFile, aViewerCS, aPSCS );
698     return result;
699 }
700
701 #ifdef WIN32
702 //======================================================================
703 // Function: translateToEMF
704 // Purpose :
705 //=======================================================================
706 bool GLViewer_Drawer::translateToEMF( HDC hDC, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aEMFCS )
707 {
708     bool result = true;
709     for( int i=0, n=myObjects.count(); i<n; i++ ) 
710         result &= myObjects[i]->translateToEMF( hDC, aViewerCS, aEMFCS );
711     return result;
712 }
713 #endif