]> SALOME platform Git repositories - modules/gui.git/blob - src/GLViewer/GLViewer_Drawer.cxx
Salome HOME
65d0dcf1fbd0383492d810a2617b97acca0c2785
[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 // Function: loadTexture
420 // Purpose :
421 //=======================================================================
422 GLuint GLViewer_Drawer::loadTexture( const QString& fileName )
423 {
424     QImage buf;
425     if ( fileName.isEmpty() || !buf.load( fileName ) )
426         return 0;
427
428     int w = buf.width();
429     int h = buf.height();
430
431     int size = 16;
432     while( size < w || size < h )
433         size = size * 2;
434
435     GLuint texture;
436     GLubyte* pixels = new GLubyte[ size * size * 4 ];
437
438     for( int i = 0; i < size; i++ )
439     {            
440         for( int j = 0; j < size; j++ )
441         {
442             GLubyte r, g, b, a;
443             if( j < w && i < h )
444             {
445                 QRgb pixel = buf.pixel( j, h - i - 1 );
446                 r = (GLubyte)qRed( pixel );
447                 g = (GLubyte)qGreen( pixel );
448                 b = (GLubyte)qBlue( pixel );
449                 a = (GLubyte)qAlpha( pixel );
450             }
451             else
452             {
453                 r = (GLubyte)255;
454                 g = (GLubyte)255;
455                 b = (GLubyte)255;
456                 a = (GLubyte)255;
457             }
458
459             int index = 4 * ( i * size + j );
460             pixels[ index ] = r;
461             pixels[ index + 1 ] = g;
462             pixels[ index + 2 ] = b;
463             pixels[ index + 3 ] = a;
464         }
465     }
466
467     //initialize texture
468     glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
469     glGenTextures( 1, &texture );
470     glBindTexture( GL_TEXTURE_2D, texture );
471     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
472     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
473     glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, size, size, 0,
474                   GL_RGBA, GL_UNSIGNED_BYTE, pixels );
475
476     delete[] pixels;
477
478     return texture;
479 }
480
481 //======================================================================
482 // Function: drawTexture
483 // Purpose :
484 //=======================================================================
485 void GLViewer_Drawer::drawTexture( GLuint texture, GLint size, GLfloat x, GLfloat y )
486 {
487     if( !texture )
488         return;
489
490     glColor4f( 1.0, 1.0, 1.0, 1.0 );
491
492     glEnable( GL_TEXTURE_2D );
493     glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
494     glAlphaFunc( GL_GREATER, 0.95F );
495     glEnable( GL_ALPHA_TEST );
496     
497     glBindTexture( GL_TEXTURE_2D, texture );
498     glBegin( GL_QUADS );
499
500     glTexCoord2f( 0.0, 0.0 );
501     glVertex3f( x-size/2., y-size/2., 0.0 );
502
503     glTexCoord2f( 0.0, 1.0 );
504     glVertex3f( x-size/2., y+size/2., 0.0 );
505
506     glTexCoord2f( 1.0, 1.0 );
507     glVertex3f( x+size/2., y+size/2., 0.0 );
508
509     glTexCoord2f( 1.0, 0.0 );
510     glVertex3f( x+size/2., y-size/2., 0.0 );
511     
512     glEnd();
513     glFlush();
514
515     glDisable( GL_ALPHA_TEST );
516     glDisable( GL_TEXTURE_2D );
517 }
518
519 //======================================================================
520 // Function: drawText
521 // Purpose :
522 //=======================================================================
523 void GLViewer_Drawer::drawText( const QString& text, GLfloat xPos, GLfloat yPos,
524                                 const QColor& color, QFont* theFont, int theSeparator, DisplayTextFormat theFormat )
525 {
526   if( theFormat == DTF_TEXTURE )
527   {
528     GLViewer_TexFont aTexFont( theFont, theSeparator );
529     aTexFont.generateTexture();
530
531     glGetIntegerv (GL_VIEWPORT, viewport);
532     glGetDoublev (GL_MODELVIEW_MATRIX, modelMatrix);
533     glGetDoublev (GL_PROJECTION_MATRIX, projMatrix);
534     status = gluProject (xPos, yPos, 0, modelMatrix, projMatrix, viewport, &winx, &winy, &winz);
535
536     glPushAttrib( GL_TRANSFORM_BIT | GL_VIEWPORT_BIT | GL_LIST_BIT );
537     glMatrixMode(GL_PROJECTION);
538     glPushMatrix();
539     glLoadIdentity();
540     glOrtho(0,viewport[2],0,viewport[3],-100,100);
541     glMatrixMode(GL_MODELVIEW);
542     glPushMatrix();
543     glLoadIdentity();
544
545     glColor3f( ( GLfloat )color.red() / 255, 
546                ( GLfloat )color.green() / 255, 
547                ( GLfloat )color.blue() / 255 );
548
549     aTexFont.drawString( text, winx, winy );
550
551     glPopMatrix();
552     glMatrixMode(GL_PROJECTION);
553     glPopMatrix();
554     glPopAttrib();
555   }
556   else if( theFormat == DTF_BITMAP )
557   {
558     glColor3f( ( GLfloat )color.red() / 255, 
559                ( GLfloat )color.green() / 255, 
560                ( GLfloat )color.blue() / 255 );
561     glRasterPos2f( xPos, yPos );
562     glListBase( displayListBase( theFont ) );
563     glCallLists( text.length(), GL_UNSIGNED_BYTE, text.local8Bit().data() );
564   }
565 }
566
567 //======================================================================
568 // Function: drawText
569 // Purpose :
570 //=======================================================================
571 void GLViewer_Drawer::drawText( GLViewer_Object* theObject )
572 {
573   if( !theObject )
574     return;
575
576   GLViewer_Text* aText = theObject->getGLText();
577   if( !aText )
578     return;
579
580   GLfloat aPosX, aPosY;
581   aText->getPosition( aPosX, aPosY );
582   // get temporary copy of font
583   QFont aTmpVarFont = aText->getFont();
584   drawText( aText->getText(), aPosX, aPosY, aText->getColor(), &aTmpVarFont, aText->getSeparator(), aText->getDisplayTextFormat() );
585 }
586
587 //======================================================================
588 // Function: drawGLText
589 // Purpose :
590 //=======================================================================
591 void GLViewer_Drawer::drawGLText( QString text, float x, float y,
592                                   int hPosition, int vPosition, QColor color, bool smallFont )
593 {
594   QFont aFont( "Arial", 10, QFont::Bold );
595   if( smallFont )
596     aFont.setPointSize( 8 );
597
598   QFontMetrics aFontMetrics( aFont );
599   float width = aFontMetrics.width( text ) / myXScale;
600   float height = aFontMetrics.height() / myXScale;
601   float gap = 5 / myXScale;
602
603   switch( hPosition )
604   {
605       case GLText_Left   : x -= ( gap + width ); break;
606       case GLText_Center : x -= width / 2; break;
607       case GLText_Right  : x += gap; break;
608       default : break;
609   }
610
611   switch( vPosition )
612   {
613       case GLText_Top    : y += height * 0.5; break;
614       case GLText_Center : y -= height * 0.5; break;
615       case GLText_Bottom : y -= height * 1.5; break;
616       default : break;
617   }
618
619   drawText( text, x, y, color, &aFont, 2, DTF_BITMAP ); // DTF_BITMAP or DTF_TEXTURE
620 }
621
622 //======================================================================
623 // Function: drawRectangle
624 // Purpose :
625 //=======================================================================
626 void GLViewer_Drawer::drawRectangle( GLViewer_Rect* rect, QColor color )
627 {
628   if( !rect )
629     return;
630
631   float x1 = rect->left();
632   float x2 = rect->right();
633   float y1 = rect->bottom();
634   float y2 = rect->top();
635   
636   glColor3f( ( GLfloat )color.red() / 255,
637     ( GLfloat )color.green() / 255,
638     ( GLfloat )color.blue() / 255 );
639   glLineWidth( 1.0 );
640   
641   glBegin( GL_LINE_LOOP );
642   glVertex2f( x1, y1 );
643   glVertex2f( x1, y2 );
644   glVertex2f( x2, y2 );
645   glVertex2f( x2, y1 );
646   glEnd();
647 }
648
649 //======================================================================
650 // Function: translateToHPGL
651 // Purpose :
652 //=======================================================================
653 bool GLViewer_Drawer::translateToHPGL( QFile& hFile, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aHPGLCS )
654 {
655     bool result = true;
656     for( int i=0, n=myObjects.count(); i<n; i++ ) 
657         result &= myObjects[i]->translateToHPGL( hFile, aViewerCS, aHPGLCS );
658     return result;
659 }
660
661 //======================================================================
662 // Function: translateToPS
663 // Purpose :
664 //=======================================================================
665 bool GLViewer_Drawer::translateToPS( QFile& hFile, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aPSCS )
666 {
667     bool result = true;
668     for( int i=0, n=myObjects.count(); i<n; i++ ) 
669         result &= myObjects[i]->translateToPS( hFile, aViewerCS, aPSCS );
670     return result;
671 }
672
673 #ifdef WIN32
674 //======================================================================
675 // Function: translateToEMF
676 // Purpose :
677 //=======================================================================
678 bool GLViewer_Drawer::translateToEMF( HDC hDC, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aEMFCS )
679 {
680     bool result = true;
681     for( int i=0, n=myObjects.count(); i<n; i++ ) 
682         result &= myObjects[i]->translateToEMF( hDC, aViewerCS, aEMFCS );
683     return result;
684 }
685 #endif