Salome HOME
1b6912b8163865d00784c79ee03c66547e2f6e0c
[modules/gui.git] / src / GLViewer / GLViewer_Drawer.cxx
1 //  Copyright (C) 2005 OPEN CASCADE
2 //
3 //  This library is free software; you can redistribute it and/or
4 //  modify it under the terms of the GNU Lesser General Public
5 //  License as published by the Free Software Foundation; either
6 //  version 2.1 of the License.
7 //
8 //  This library is distributed in the hope that it will be useful,
9 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
10 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 //  Lesser General Public License for more details.
12 //
13 //  You should have received a copy of the GNU Lesser General Public
14 //  License along with this library; if not, write to the Free Software
15 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 //  See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org
18 //
19 //  Author : OPEN CASCADE
20 //
21
22 // File:      GLViewer_Drawer.cxx
23 // Created:   November, 2004
24
25 //#include <GLViewerAfx.h>
26 #include "GLViewer_Drawer.h"
27 #include "GLViewer_Object.h"
28 #include "GLViewer_Text.h"
29 #include "GLViewer_ViewFrame.h"
30 #include "GLViewer_ViewPort2d.h"
31
32 #ifndef WIN32
33 #include <GL/glx.h>
34 #endif
35
36 #include <gp_Pnt2d.hxx>
37
38 #include <qimage.h>
39 #include <qpainter.h>
40
41 #define TEXT_GAP    5
42 // Two texture components for texmapped fonts: luminance and alpha
43 #define NB_TEX_COMP 2
44 // A font is split into rows each containing 32 characters
45 #define TEX_ROW_LEN 32
46 // Gap in pixels between two character rows in a font texture
47 #define TEX_ROW_GAP 2
48
49 GLfloat modelMatrix[16];
50
51
52 //! code of first font symbol
53 static int FirstSymbolNumber = 32;
54 //! code of last font symbol
55 static int LastSymbolNumber = 127;
56
57 QMap<GLViewer_TexFindId,GLViewer_TexIdStored> GLViewer_TexFont::TexFontBase;
58 QMap<GLViewer_TexFindId,GLuint>               GLViewer_TexFont::BitmapFontCache; 
59
60 /*!
61   Clears all generated fonts
62 */
63 void GLViewer_TexFont::clearTextBases()
64 {
65   //cout << "Clear font map" << endl;
66   TexFontBase.clear();
67   BitmapFontCache.clear();
68 }
69
70 /*!
71   Default constructor
72 */
73 GLViewer_TexFont::GLViewer_TexFont()
74 : myMaxRowWidth( 0 ), myFontHeight( 0 )
75 {
76     myQFont = QFont::defaultFont();
77     mySeparator = 2;
78     myIsResizeable = false;
79     myMinMagFilter = GL_LINEAR;
80
81     init();
82 }
83
84 /*!
85   Constructor
86   \param theFont         - a base font
87   \param theSeparator    - separator between letters
88   \param theIsResizeable - specifies whether text drawn by this object can be scaled along with the scene
89   \param theMinMagFilter - min/mag filter, affects text sharpness
90 */
91 GLViewer_TexFont::GLViewer_TexFont( QFont* theFont, int theSeparator, bool theIsResizeable, GLuint theMinMagFilter )
92 : myMaxRowWidth( 0 ), myFontHeight( 0 )
93 {
94     myQFont = *theFont;
95     mySeparator = theSeparator;
96     myIsResizeable = theIsResizeable;
97     myMinMagFilter = theMinMagFilter;
98
99     init();
100 }
101
102 /*!
103   Destructor
104 */
105 GLViewer_TexFont::~GLViewer_TexFont()
106 {
107     delete[] myWidths;
108     delete[] myPositions;
109
110
111 /*!
112   Initializes font parameters
113 */
114 void GLViewer_TexFont::init()
115 {
116     myNbSymbols = LastSymbolNumber - FirstSymbolNumber + 1;
117
118     // It is unsafe to draw all characters in a single row -
119     // this leads to problems on some graphic cards with small GL_MAX_TEXTURE_SIZE.
120     // So splitting the characters into rows each containing 32 characters (or less).
121     // Assuming contant height of each row (64 pixels) to simplify texture mapping.
122     // However, this can be improved if necessary.
123     QFontMetrics aFM( myQFont ); 
124     myFontHeight = aFM.height();
125     
126     myWidths    = new int[myNbSymbols];
127     myPositions = new int[myNbSymbols];
128
129     for( int i = 0, k = FirstSymbolNumber, aWidth = 0; i < myNbSymbols; i++, k++ )
130     {
131         // is it time to start a new row?
132         if ( !( i % TEX_ROW_LEN ) )
133         {
134           if( aWidth > myMaxRowWidth )
135             myMaxRowWidth = aWidth;
136           aWidth = 0;
137         }
138         myWidths[i]    = aFM.width( k );
139         myPositions[i] = aWidth;
140         aWidth += myWidths[i] + 2;
141     }
142
143     myTexFontWidth  = 0;
144     myTexFontHeight = 0;
145 }
146   
147 /*!
148   Generating font texture
149 */
150 bool GLViewer_TexFont::generateTexture()
151 {
152     GLViewer_TexFindId aFindFont;
153     aFindFont.myFontFamily = myQFont.family();//myQFont.toString();
154     aFindFont.myIsBold = myQFont.bold();
155     aFindFont.myIsItal = myQFont.italic();
156     aFindFont.myIsUndl = myQFont.underline();
157     aFindFont.myPointSize = myQFont.pointSize();
158     aFindFont.myViewPortId = size_t(QGLContext::currentContext());
159         
160     if( TexFontBase.contains( aFindFont ) )
161     {
162         GLViewer_TexIdStored aTexture = TexFontBase[ aFindFont ];
163         myTexFont = aTexture.myTexFontId;
164         myTexFontWidth = aTexture.myTexFontWidth;
165         myTexFontHeight = aTexture.myTexFontHeight;
166     }    
167     else    
168     {
169         // Adding some pixels to have a gap between rows
170         int aRowPixelHeight = myFontHeight + TEX_ROW_GAP;
171         int aDescent = QFontMetrics( myQFont ).descent();
172
173         int aNumRows = myNbSymbols / TEX_ROW_LEN;
174         if ( myNbSymbols % TEX_ROW_LEN ) 
175           aNumRows++;
176         int pixelsHight = aNumRows * aRowPixelHeight;
177
178         myTexFontWidth  = 64;
179         myTexFontHeight = 64;
180
181         while( myTexFontWidth < myMaxRowWidth )
182             myTexFontWidth <<= 1;
183         while( myTexFontHeight < pixelsHight )
184             myTexFontHeight <<= 1;
185         
186         // Checking whether the texture dimensions for the requested font
187         // do not exceed the maximum size supported by the OpenGL implementation
188         int maxSize;
189         glGetIntegerv( GL_MAX_TEXTURE_SIZE, &maxSize );
190         if ( myTexFontWidth > maxSize || myTexFontHeight > maxSize )
191           return false;
192
193         QPixmap aPixmap( myTexFontWidth, myTexFontHeight );
194         aPixmap.fill( QColor( 0, 0, 0) );
195         QPainter aPainter( &aPixmap );
196         aPainter.setFont( myQFont );
197         int row;
198         for( int l = 0; l < myNbSymbols; l++  )
199         {
200             row = l / TEX_ROW_LEN;
201             QString aLetter;
202             aLetter += (char)(FirstSymbolNumber + l);
203             aPainter.setPen( QColor( 255,255,255) );
204             aPainter.drawText( myPositions[l], ( row + 1 ) * aRowPixelHeight - aDescent, aLetter );
205         }
206     
207         QImage aImage = aPixmap.convertToImage();
208
209         //int qqq = 0;
210         //if (qqq)
211         //  aImage.save("w:\\work\\CATHARE\\texture.png", "PNG");
212
213         char* pixels = new char[myTexFontWidth * myTexFontHeight * NB_TEX_COMP];
214
215         for( int i = 0; i < myTexFontHeight; i++ )
216         {            
217             for( int j = 0; j < myTexFontWidth;  j++ )
218             {
219                 int aRed = qRed( aImage.pixel( j, myTexFontHeight - i - 1 ) );
220                 int aGreen = qGreen( aImage.pixel( j, myTexFontHeight - i - 1 ) );
221                 int aBlue = qBlue( aImage.pixel( j, myTexFontHeight - i - 1 ) );
222           
223                 if( aRed != 0 || aGreen != 0 || aBlue != 0 )
224                 {
225                     pixels[i * myTexFontWidth * NB_TEX_COMP + j * NB_TEX_COMP] = (GLubyte)( (aRed + aGreen + aBlue)/3 );
226                     pixels[i * myTexFontWidth * NB_TEX_COMP + j * NB_TEX_COMP + 1]= (GLubyte) 255;
227                 }
228                 else
229                 {
230                     pixels[i * myTexFontWidth * NB_TEX_COMP + j * NB_TEX_COMP] = (GLubyte) 0;
231                     pixels[i * myTexFontWidth * NB_TEX_COMP + j * NB_TEX_COMP + 1]= (GLubyte) 0;
232                 }                
233             }
234         }
235
236         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
237         glGenTextures(1, &myTexFont);
238         glBindTexture(GL_TEXTURE_2D, myTexFont);  
239         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, myMinMagFilter);
240         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, myMinMagFilter);
241         glTexImage2D(GL_TEXTURE_2D, 
242                      0, 
243                      GL_INTENSITY, 
244                      myTexFontWidth,
245                      myTexFontHeight, 
246                      0, 
247                      GL_LUMINANCE_ALPHA, 
248                      GL_UNSIGNED_BYTE, 
249                      pixels);
250     
251         delete[] pixels;
252         
253         GLViewer_TexIdStored aTexture;
254         aTexture.myTexFontId = myTexFont;
255         aTexture.myTexFontWidth = myTexFontWidth;
256         aTexture.myTexFontHeight = myTexFontHeight;
257
258         TexFontBase.insert( aFindFont, aTexture );
259     }
260     return true;
261 }
262
263 /*!
264   Drawing string in viewer
265   \param theStr - string to be drawn
266   \param theX - X position
267   \param theY - Y position
268   \param theScale - scale coefficient
269 */
270 void GLViewer_TexFont::drawString( QString theStr, GLdouble theX , GLdouble theY, GLfloat theScale )
271 {
272     // Adding some pixels to have a gap between rows
273     int aRowPixelHeight = myFontHeight + TEX_ROW_GAP;
274
275     float aXScale = 1.f, aYScale = 1.f;
276     if ( !myIsResizeable )
277     {
278       glGetFloatv (GL_MODELVIEW_MATRIX, modelMatrix);
279       aXScale = modelMatrix[0];
280       aYScale = modelMatrix[5];     
281     } 
282     else if ( theScale > 0.f )
283     {
284       aXScale = aXScale / theScale;
285       aYScale = aYScale / theScale;
286     }
287
288     // store attributes
289     glPushAttrib( GL_ENABLE_BIT | GL_TEXTURE_BIT );
290
291     glEnable(GL_TEXTURE_2D);
292     glPixelTransferi(GL_MAP_COLOR, 0);
293
294     glAlphaFunc(GL_GEQUAL, 0.05F);
295     glEnable(GL_ALPHA_TEST);
296
297     glEnable(GL_BLEND);
298     glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
299
300     glBindTexture(GL_TEXTURE_2D, myTexFont);
301     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
302
303     glBegin(GL_QUADS);
304
305     float aLettBeginS, aLettEndS, aLettBeginT, aLettEndT;
306     float aDY = ( aRowPixelHeight - 1 ) / aYScale, aDX;
307     char aLetter;
308     int aLettIndex, row;
309     for( int i = 0; i < theStr.length(); i++ )
310     {
311         aLetter    = theStr.data()[i];
312         aLettIndex = (int)aLetter - FirstSymbolNumber;
313         row        = aLettIndex / TEX_ROW_LEN;
314
315         aLettBeginS = (float)myPositions[aLettIndex] / ( (float)myTexFontWidth - 1.f );
316         aLettEndS   = aLettBeginS + ( (float)myWidths[aLettIndex] - 1.f ) / ( (float)myTexFontWidth - 1.f );
317         aLettBeginT = ( myTexFontHeight - ( row + 1 ) * aRowPixelHeight ) / ( (float)myTexFontHeight - 1.f ); 
318         aLettEndT   = aLettBeginT + ( (float)aRowPixelHeight - 1.f ) / ( (float)myTexFontHeight - 1.f );
319
320         aDX = ( (float)myWidths[aLettIndex] - 1.f ) / aXScale;
321
322         glTexCoord2f( aLettBeginS, aLettBeginT ); glVertex3f( theX,       theY,       1.f );
323         glTexCoord2f( aLettBeginS, aLettEndT   ); glVertex3f( theX,       theY + aDY, 1.f );
324         glTexCoord2f( aLettEndS,   aLettEndT   ); glVertex3f( theX + aDX, theY + aDY, 1.f );
325         glTexCoord2f( aLettEndS,   aLettBeginT ); glVertex3f( theX + aDX, theY,       1.f );
326
327         theX += aDX + mySeparator / aXScale;
328     }
329
330     glEnd();
331     // restore attributes
332     glPopAttrib();
333 }
334
335 /*!
336   \return width of string in pixels
337 */
338 int GLViewer_TexFont::getStringWidth( QString theStr )
339 {
340     int aWidth = 0;
341     for( int i = 0; i < theStr.length(); i ++ )
342     {
343         char aLetter = theStr.data()[i];
344         int aLettIndex = (int)aLetter - FirstSymbolNumber;
345         aWidth += myWidths[aLettIndex] + mySeparator;
346     }
347
348     return aWidth;
349 }
350
351 /*!
352   \return height of string in pixels
353 */
354 int GLViewer_TexFont::getStringHeight()
355 {
356     QFontMetrics aFM( myQFont );
357     return aFM.height();
358 }
359
360 /*!
361   Generates list base for bitmap fonts
362 */
363 static GLuint displayListBase( QFont* theFont )
364 {
365   if ( !theFont )
366     return 0;
367   GLuint aList = 0;
368   //static QMap<GLViewer_TexFindId, GLuint> fontCache;
369   GLViewer_TexFindId aFindFont;
370   aFindFont.myFontFamily = theFont->family();//theFont->toString();
371   aFindFont.myIsBold = theFont->bold();
372   aFindFont.myIsItal = theFont->italic();
373   aFindFont.myIsUndl = theFont->underline();
374   aFindFont.myPointSize = theFont->pointSize();
375
376 #ifdef WIN32
377   HGLRC ctx = ::wglGetCurrentContext();
378   if ( !ctx )
379     return aList;  
380   
381   aFindFont.myViewPortId = (int)ctx;
382
383   if ( GLViewer_TexFont::BitmapFontCache.contains( aFindFont ) )
384     aList = GLViewer_TexFont::BitmapFontCache[aFindFont];
385   else
386   {
387     GLuint listBase = 0;
388     QMap<GLViewer_TexFindId, GLuint>::iterator it = GLViewer_TexFont::BitmapFontCache.begin();
389     for ( ; it != GLViewer_TexFont::BitmapFontCache.end(); ++it )
390     {
391       if ( it.key().myViewPortId == (int)ctx && it.data() > listBase )
392         listBase = it.data();
393     }
394     listBase += 256;
395
396     HDC glHdc = ::wglGetCurrentDC();
397     ::SelectObject( glHdc, theFont->handle() );
398     if ( !::wglUseFontBitmaps( glHdc, 0, 256, listBase ) )
399       listBase = 0;
400     aList = listBase;
401     GLViewer_TexFont::BitmapFontCache[aFindFont] = aList;
402   }
403 #else //X Window
404   Display* aDisp = glXGetCurrentDisplay();
405   if( !aDisp )
406   {
407 #ifdef _DEBUG_
408     printf( "Can't find current dislay\n" );
409 #endif
410     return aList;
411   }
412   
413   GLXContext aCont = glXGetCurrentContext();
414   if( !aCont )
415   {
416 #ifdef _DEBUG_
417     printf( "Can't find current context\n" );
418 #endif
419     return aList;
420   }
421
422   aFindFont.myViewPortId = size_t(aCont);
423
424   if ( GLViewer_TexFont::BitmapFontCache.contains( aFindFont ) )
425     aList = GLViewer_TexFont::BitmapFontCache[aFindFont];
426   else
427   {
428     GLuint listBase = 0;
429     QMap<GLViewer_TexFindId, GLuint>::iterator it = GLViewer_TexFont::BitmapFontCache.begin();
430     for ( ; it != GLViewer_TexFont::BitmapFontCache.end(); ++it )
431     {
432       if ( it.key().myViewPortId == size_t(aCont) && it.data() > listBase )
433         listBase = it.data();
434     }
435     listBase += 256;
436     
437     //glXUseXFont( (Font)(theFont->handle()), 0, 256, listBase );
438     int aFontCont = 0;
439     QString aFontDef = theFont->toString();
440     char** xFontList = XListFonts( aDisp, aFontDef.latin1()/*aFindFont.myFontString.data()*/, 1, &aFontCont  );
441     if( !theFont->handle() )
442     {       
443 #ifdef _DEBUG_
444       printf( "Can't load font %s. loading default font....\n", aFontDef.latin1()/*aFindFont.myFontString.data()*/ );
445 #endif
446       QString aFontMask ("-*-*-*-r-*-*-");
447       aFontMask += aFontDef/*aFindFont.myFontString*/.section( ',', 1, 1 );
448 #ifdef _DEBUG_
449       printf( "Height of Default font: %s\n", aFontDef/*aFindFont.myFontString*/.section( ',', 1, 1 ).data() );
450 #endif
451       aFontMask += "-*-*-*-m-*-*-*";
452       xFontList = XListFonts( aDisp, aFontMask.data()/*"-*-*-*-r-*-*-12-*-*-*-m-*-*-*"*/, 1, &aFontCont  );
453       if( aFontCont == 0 )
454       {      
455 #ifdef _DEBUG_
456         printf( "Can't load default font\n" );
457 #endif
458         return 0;
459       }
460       glXUseXFont( (Font)(XLoadFont( aDisp,xFontList[0] )), 0, 256, listBase );
461     }
462     else
463       glXUseXFont( (Font)(theFont->handle()), 0, 256, listBase );
464     
465     aList = listBase;
466     GLViewer_TexFont::BitmapFontCache[aFindFont] = aList;
467   }
468
469 #endif
470
471   return aList;
472 }
473
474 /*!
475   Default constructor
476 */
477 GLViewer_Drawer::GLViewer_Drawer()
478 : myFont( "Helvetica", 10, QFont::Bold )
479 {
480   myXScale = myYScale = 0.0;
481   myObjects.clear();
482   myTextList = 0/*-1*/;
483   myObjectType = "GLViewer_Object";
484   myPriority = 0;
485   myTextFormat = DTF_BITMAP;
486   myTextScale = 0.125;
487 }
488
489 /*!
490   Destructor
491 */
492 GLViewer_Drawer::~GLViewer_Drawer()
493 {
494   myObjects.clear();
495   glDeleteLists( myTextList, 1 );
496 }
497
498 /*!
499   Clears all generated textures
500 */
501 void GLViewer_Drawer::destroyAllTextures()
502 {
503     QMap<GLViewer_TexFindId,GLViewer_TexIdStored>::Iterator anIt= GLViewer_TexFont::TexFontBase.begin();
504     QMap<GLViewer_TexFindId,GLViewer_TexIdStored>::Iterator anEndIt= GLViewer_TexFont::TexFontBase.end();
505
506     for( ; anIt != anEndIt; anIt++ )
507         glDeleteTextures( 1, &(anIt.data().myTexFontId) );
508 }
509
510 /*!
511   Enables and disables antialiasing in Open GL (for points, lines and polygons).
512   \param on - if it is true, antialiasing is enabled
513 */
514 void GLViewer_Drawer::setAntialiasing(const bool on)
515 {
516         if (on)
517         {
518     glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
519     glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
520
521                 glEnable(GL_POINT_SMOOTH);
522                 glEnable(GL_LINE_SMOOTH);
523                 glEnable(GL_POLYGON_SMOOTH);
524                 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 
525                 glEnable (GL_BLEND);
526         }
527         else
528         {
529                 glDisable(GL_POINT_SMOOTH);
530                 glDisable(GL_LINE_SMOOTH);
531                 glDisable(GL_POLYGON_SMOOTH);
532                 glBlendFunc (GL_ONE, GL_ZERO);
533                 glDisable (GL_BLEND);
534         }
535 }
536
537 /*! Loads texture from file
538   \param fileName - the name of texture file
539   \param x_size   - the horizontal size of picture ( less or equal texture horizontal size )
540   \param y_size   - the vertical size of picture ( less or equal texture vertical size )
541   \param t_size   - the size of texture ( texture vertical size equals texture horizontal size )
542 */
543 GLuint GLViewer_Drawer::loadTexture( const QString& fileName,
544                                      GLint* x_size,
545                                      GLint* y_size,
546                                      GLint* t_size )
547 {
548     QImage buf;
549     if ( fileName.isEmpty() || !buf.load( fileName ) )
550         return 0;
551
552     int w = buf.width();
553     int h = buf.height();
554
555     int size = 16;
556     while( size < w || size < h )
557         size = size * 2;
558
559     GLuint texture;
560     GLubyte* pixels = new GLubyte[ size * size * 4 ];
561
562     for( int i = 0; i < size; i++ )
563     {            
564         for( int j = 0; j < size; j++ )
565         {
566             GLubyte r, g, b, a;
567             if( j < w && i < h )
568             {
569                 QRgb pixel = buf.pixel( j, h - i - 1 );
570                 r = (GLubyte)qRed( pixel );
571                 g = (GLubyte)qGreen( pixel );
572                 b = (GLubyte)qBlue( pixel );
573                 a = (GLubyte)qAlpha( pixel );
574             }
575             else
576             {
577                 r = (GLubyte)255;
578                 g = (GLubyte)255;
579                 b = (GLubyte)255;
580                 a = (GLubyte)255;
581             }
582
583             int index = 4 * ( i * size + j );
584             pixels[ index ] = r;
585             pixels[ index + 1 ] = g;
586             pixels[ index + 2 ] = b;
587             pixels[ index + 3 ] = a;
588         }
589     }
590
591     //initialize texture
592     glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
593     glGenTextures( 1, &texture );
594     glBindTexture( GL_TEXTURE_2D, texture );
595     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
596     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
597     glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, size, size, 0,
598                   GL_RGBA, GL_UNSIGNED_BYTE, pixels );
599
600     delete[] pixels;
601
602     if ( x_size )
603       *(x_size) = w;
604
605     if ( y_size )
606       *(y_size) = h;
607
608     if ( t_size )
609       *(t_size) = size;
610
611     return texture;
612 }
613
614 /*! Draw square texture
615    \param texture - the texture ID
616    \param size    - the size of square texture
617    \param x       - x coord
618    \param y       - y coord
619 */
620 void GLViewer_Drawer::drawTexture( GLuint texture, GLint size, GLfloat x, GLfloat y )
621 {
622     /*float xScale = myXScale;
623     float yScale = myYScale;
624
625     glColor4f( 1.0, 1.0, 1.0, 1.0 );
626
627     glEnable( GL_TEXTURE_2D );
628     glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
629     glAlphaFunc( GL_GREATER, 0.95F );
630     glEnable( GL_ALPHA_TEST );
631     
632     glBindTexture( GL_TEXTURE_2D, texture );
633     glBegin( GL_QUADS );
634
635     glTexCoord2f( 0.0, 0.0 );
636     glVertex3f( x-size/2./xScale, y-size/2./yScale, 0.0 );
637
638     glTexCoord2f( 0.0, 1.0 );
639     glVertex3f( x-size/2./xScale, y+size/2./yScale, 0.0 );
640
641     glTexCoord2f( 1.0, 1.0 );
642     glVertex3f( x+size/2./xScale, y+size/2./yScale, 0.0 );
643
644     glTexCoord2f( 1.0, 0.0 );
645     glVertex3f( x+size/2./xScale, y-size/2./yScale, 0.0 );
646     
647     glEnd();
648     glFlush();
649
650     glDisable( GL_ALPHA_TEST );
651     glDisable( GL_TEXTURE_2D );*/
652
653   drawTexture( texture, size, size, x, y );
654 }
655
656 /*! Draw texture
657    \param texture - the texture ID
658    \param x_size  - the horizontal size of texture
659    \param y_size  - the vertical size of texture
660    \param x       - x coord
661    \param y       - y coord
662 */
663 void GLViewer_Drawer::drawTexture( GLuint texture, GLint x_size, GLint y_size, GLfloat x, GLfloat y )
664 {
665     /*float xScale = myXScale;
666     float yScale = myYScale;
667
668     glColor4f( 1.0, 1.0, 1.0, 1.0 );
669
670     glEnable( GL_TEXTURE_2D );
671     glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
672     glAlphaFunc( GL_GREATER, 0.95F );
673     glEnable( GL_ALPHA_TEST );
674     
675     glBindTexture( GL_TEXTURE_2D, texture );
676     glBegin( GL_QUADS );
677
678     glTexCoord2f( 0.0, 0.0 );
679     glVertex3f( x-x_size/2./xScale, y-y_size/2./yScale, 0.0 );
680
681     glTexCoord2f( 0.0, 1.0 );
682     glVertex3f( x-x_size/2./xScale, y+y_size/2./yScale, 0.0 );
683
684     glTexCoord2f( 1.0, 1.0 );
685     glVertex3f( x+x_size/2./xScale, y+y_size/2./yScale, 0.0 );
686
687     glTexCoord2f( 1.0, 0.0 );
688     glVertex3f( x+x_size/2./xScale, y-y_size/2./yScale, 0.0 );
689     
690     glEnd();
691     glFlush();
692
693     glDisable( GL_ALPHA_TEST );
694     glDisable( GL_TEXTURE_2D );*/
695   drawTexturePart( texture, 1.0, 1.0, x_size, y_size, x, y );
696 }
697
698 /*! Draw texture part
699    \param texture - the texture ID
700    \param x_ratio - the horizontal ratio of texture part
701    \param y_ratio - the vertical ratio of texture part
702    \param x_size  - the horizontal size of texture
703    \param y_size  - the vertical size of texture
704    \param x       - x coord
705    \param y       - y coord
706    \param scale   - common scale factor ( if = 0, use drawer scales )
707 */
708 void GLViewer_Drawer::drawTexturePart( GLuint texture,
709                                        GLfloat x_ratio,
710                                        GLfloat y_ratio,
711                                        GLfloat x_size,
712                                        GLfloat y_size,
713                                        GLfloat x,
714                                        GLfloat y,
715                                        GLfloat scale )
716 {
717   if( !texture )
718     return;
719
720   float xScale = scale > 0. ? 1./scale : myXScale;
721   float yScale = scale > 0. ? 1./scale : myYScale;
722
723   glColor4f( 1.0, 1.0, 1.0, 1.0 );
724
725
726   glEnable( GL_TEXTURE_2D );
727   glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
728   bool hasAlpha = glIsEnabled( GL_ALPHA_TEST );
729   glDisable( GL_ALPHA_TEST );
730
731   glBindTexture( GL_TEXTURE_2D, texture );
732   glBegin( GL_QUADS );
733
734   glTexCoord2f( 0.0, 0.0 );
735   glVertex3f( x-x_size/2./xScale, y-y_size/2./yScale, 0.0 );
736
737   glTexCoord2f( 0.0, y_ratio );
738   glVertex3f( x-x_size/2./xScale, y+y_size/2./yScale, 0.0 );
739
740   glTexCoord2f( x_ratio, y_ratio );
741   glVertex3f( x+x_size/2./xScale, y+y_size/2./yScale, 0.0 );
742
743   glTexCoord2f( x_ratio, 0.0 );
744   glVertex3f( x+x_size/2./xScale, y-y_size/2./yScale, 0.0 );
745   
746   glEnd();
747   glFlush();
748
749   if ( hasAlpha )
750     glEnable( GL_ALPHA_TEST );
751
752   glDisable( GL_TEXTURE_2D );
753 }
754
755 /*!
756   Draw text
757   \param text - text to be drawn
758   \param xPos - x position
759   \param yPos - y position
760   \param color - color of text
761   \param theFont - font of text
762   \param theSeparator - letter separator
763   \param theFormat - text format (by default DTF_BITMAP)
764 */
765 void GLViewer_Drawer::drawText( const QString& text, GLfloat xPos, GLfloat yPos,
766                                 const QColor& color, QFont* theFont, int theSeparator, DisplayTextFormat theFormat )
767 {
768   glColor3f( ( GLfloat )color.red() / 255, 
769              ( GLfloat )color.green() / 255, 
770              ( GLfloat )color.blue() / 255 );
771
772   if( theFormat != DTF_BITMAP )
773   {
774     GLViewer_TexFont aTexFont( theFont, theSeparator, theFormat == DTF_TEXTURE_SCALABLE, GL_LINEAR );
775     // Font texture was not found or generated --> cannot draw text
776     if ( !aTexFont.generateTexture() )
777       return;
778
779     if ( theFormat == DTF_TEXTURE_SCALABLE )
780       aTexFont.drawString( text, xPos, yPos, textScale() );
781     else
782       aTexFont.drawString( text, xPos, yPos );
783   }
784   else
785   {
786     glRasterPos2f( xPos, yPos );
787     glListBase( displayListBase( theFont ) );
788     glCallLists( text.length(), GL_UNSIGNED_BYTE, text.local8Bit().data() );
789   }
790 }
791
792 /*!
793   Draws object-text
794 */
795 void GLViewer_Drawer::drawText( GLViewer_Object* theObject )
796 {
797   if( !theObject )
798     return;
799
800   GLViewer_Text* aText = theObject->getGLText();
801   if( !aText )
802     return;
803
804   GLfloat aPosX, aPosY;
805   aText->getPosition( aPosX, aPosY );
806   // get temporary copy of font
807   QFont aTmpVarFont = aText->getFont();
808   drawText( aText->getText(), aPosX, aPosY, aText->getColor(), &aTmpVarFont, aText->getSeparator(), aText->getDisplayTextFormat() );
809 }
810
811 /*! Draw text
812    \param text      - the text string
813    \param x         - x coord
814    \param y         - y coord
815    \param hPosition - horizontal alignment
816    \param vPosition - vertical alignment
817    \param color     - text color
818    \param smallFont - font format
819 */
820 void GLViewer_Drawer::drawGLText( QString text, float x, float y,
821                                   int hPosition, int vPosition, QColor color, bool smallFont )
822 {
823   QFont aFont( myFont );
824   if( smallFont )
825     aFont.setPointSize( int(aFont.pointSize() * 0.8) );
826
827   GLfloat scale = textScale() > 0. ? textScale() : 1.;
828
829   QFontMetrics aFontMetrics( aFont );
830   float width  = myTextFormat == DTF_TEXTURE_SCALABLE ? aFontMetrics.width( text ) * scale : aFontMetrics.width( text ) / myXScale;
831   float height = myTextFormat == DTF_TEXTURE_SCALABLE ? aFontMetrics.height() * scale : aFontMetrics.height() / myYScale;
832   float gap = 5 / myXScale;
833
834   switch( hPosition )
835   {
836       case GLText_Left   : x -= ( gap + width ); break;
837       case GLText_Center : x -= width / 2; break;
838       case GLText_Right  : x += gap; break;
839       default : break;
840   }
841
842   switch( vPosition )
843   {
844       case GLText_Top    : y += height * 0.5; break;
845       case GLText_Center : y -= height * 0.5; break;
846       case GLText_Bottom : y -= height * 1.5; break;
847       default : break;
848   }
849
850   drawText( text, x, y, color, &aFont, 2, myTextFormat );
851 }
852
853 /*!
854   \return a rectangle of text (without viewer scale)
855 */
856 GLViewer_Rect GLViewer_Drawer::textRect( const QString& text ) const
857 {
858   GLfloat scale = textScale() > 0. ? textScale() : 1.;
859
860   QFontMetrics aFontMetrics( myFont );
861   float width  = myTextFormat == DTF_TEXTURE_SCALABLE ? aFontMetrics.width( text ) * scale : aFontMetrics.width( text );
862   float height = myTextFormat == DTF_TEXTURE_SCALABLE ? aFontMetrics.height() * scale : aFontMetrics.height();
863
864   return GLViewer_Rect( 0, width, height, 0 );
865 }
866
867 /*!
868   Draws rectangle
869   \param rect - instance of primitive
870   \param color - color of primitive
871 */
872 void GLViewer_Drawer::drawRectangle( GLViewer_Rect* rect, QColor color )
873 {
874   if( !rect )
875     return;
876
877   float x1 = rect->left();
878   float x2 = rect->right();
879   float y1 = rect->bottom();
880   float y2 = rect->top();
881   
882   glColor3f( ( GLfloat )color.red() / 255,
883     ( GLfloat )color.green() / 255,
884     ( GLfloat )color.blue() / 255 );
885   glLineWidth( 1.0 );
886   
887   glBegin( GL_LINE_LOOP );
888   glVertex2f( x1, y1 );
889   glVertex2f( x1, y2 );
890   glVertex2f( x2, y2 );
891   glVertex2f( x2, y1 );
892   glEnd();
893 }
894
895 /*!
896   Saves object to file with format of HPGL
897   \param hFile - file
898   \param aViewerCS - viewer co-ordinate system
899   \param aHPGLCS - paper co-ordinate system
900 */
901 bool GLViewer_Drawer::translateToHPGL( QFile& hFile, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aHPGLCS )
902 {
903     bool result = true;
904     for( int i=0, n=myObjects.count(); i<n; i++ ) 
905         result &= myObjects[i]->translateToHPGL( hFile, aViewerCS, aHPGLCS );
906     return result;
907 }
908
909 /*!
910   Saves object to file with format of PostScript
911   \param hFile - file
912   \param aViewerCS - viewer co-ordinate system
913   \param aPSCS - paper co-ordinate system
914 */
915 bool GLViewer_Drawer::translateToPS( QFile& hFile, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aPSCS )
916 {
917     bool result = true;
918     for( int i=0, n=myObjects.count(); i<n; i++ ) 
919         result &= myObjects[i]->translateToPS( hFile, aViewerCS, aPSCS );
920     return result;
921 }
922
923 #ifdef WIN32
924 /*!
925   Saves object to file with format of EMF
926   \param hFile - file
927   \param aViewerCS - viewer co-ordinate system
928   \param aEMFCS - paper co-ordinate system
929 */
930 bool GLViewer_Drawer::translateToEMF( HDC hDC, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aEMFCS )
931 {
932     bool result = true;
933     for( int i=0, n=myObjects.count(); i<n; i++ ) 
934         result &= myObjects[i]->translateToEMF( hDC, aViewerCS, aEMFCS );
935     return result;
936 }
937 #endif
938
939 /*!
940   Draws rectangle
941   \param rect - instance of primitive
942   \param lineWidth - width of line
943   \param gap - gap of rectangle
944   \param color - color of primitive
945   \param filled - if it is true, then rectangle will be drawn filled with color "fillingColor"
946   \param fillingColor - color of filling
947 */
948 void GLViewer_Drawer::drawRectangle( GLViewer_Rect* rect, GLfloat lineWidth, GLfloat gap,
949                                      QColor color, bool filled, QColor fillingColor )
950 {
951   if( !rect )
952     return;
953
954   float x1 = rect->left() - gap;
955   float x2 = rect->right() + gap;
956   float y1 = rect->bottom() - gap;
957   float y2 = rect->top() + gap;
958   
959   if( filled )
960   {
961     glColor3f( ( GLfloat )fillingColor.red() / 255,
962       ( GLfloat )fillingColor.green() / 255,
963       ( GLfloat )fillingColor.blue() / 255 );
964     glBegin( GL_POLYGON );
965     glVertex2f( x1, y1 );
966     glVertex2f( x1, y2 );
967     glVertex2f( x2, y2 );
968     glVertex2f( x2, y1 );
969     glEnd();
970   }
971
972   glColor3f( ( GLfloat )color.red() / 255,
973     ( GLfloat )color.green() / 255,
974     ( GLfloat )color.blue() / 255 );
975   glLineWidth( lineWidth );
976   
977   glBegin( GL_LINE_LOOP );
978   glVertex2f( x1, y1 );
979   glVertex2f( x1, y2 );
980   glVertex2f( x2, y2 );
981   glVertex2f( x2, y1 );
982   glEnd();
983 }
984
985 /*!
986   Draws contour
987   \param pntList - list of points
988   \param color - color of contour
989   \param lineWidth - width of line
990 */
991 void GLViewer_Drawer::drawContour( const GLViewer_PntList& pntList, QColor color, GLfloat lineWidth )
992 {
993   glColor3f( ( GLfloat )color.red() / 255,
994     ( GLfloat )color.green() / 255,
995     ( GLfloat )color.blue() / 255 );
996   glLineWidth( lineWidth );
997   
998   glBegin( GL_LINES );
999   QValueList<GLViewer_Pnt>::const_iterator it = pntList.begin();
1000   for( ; it != pntList.end(); ++it )
1001     glVertex2f( (*it).x(), (*it).y() );
1002   glEnd();
1003 }
1004
1005 /*!
1006   Draws rectangular contour
1007   \param rect - instance of rectangle
1008   \param color - color of primitive
1009   \param lineWidth - width of line
1010   \param pattern - pattern of line
1011   \param isStripe - enables line stipple
1012 */
1013 void GLViewer_Drawer::drawContour( GLViewer_Rect* rect, QColor color, GLfloat lineWidth,
1014                                    GLushort pattern, bool isStripe )
1015 {
1016   float x1 = rect->left();
1017   float x2 = rect->right();
1018   float y1 = rect->bottom();
1019   float y2 = rect->top();
1020   
1021   glColor3f( ( GLfloat )color.red() / 255,
1022     ( GLfloat )color.green() / 255,
1023     ( GLfloat )color.blue() / 255 );
1024   glLineWidth( lineWidth );
1025   
1026   if ( isStripe )
1027   {
1028     glEnable( GL_LINE_STIPPLE );
1029     glLineStipple( 1, pattern );
1030   }
1031
1032   glBegin( GL_LINE_LOOP );
1033
1034   glVertex2f( x1, y1 );
1035   glVertex2f( x1, y2 );
1036   glVertex2f( x2, y2 );
1037   glVertex2f( x2, y1 );
1038
1039   glEnd();
1040   glDisable( GL_LINE_STIPPLE );
1041 }
1042
1043 /*!
1044   Draws polygon
1045   \param pntList - list of points
1046   \param color - color of polygon
1047 */
1048 void GLViewer_Drawer::drawPolygon( const GLViewer_PntList& pntList, QColor color )
1049 {
1050   glColor3f( ( GLfloat )color.red() / 255,
1051     ( GLfloat )color.green() / 255,
1052     ( GLfloat )color.blue() / 255 );
1053   glBegin( GL_POLYGON );
1054   QValueList<GLViewer_Pnt>::const_iterator it = pntList.begin();
1055   for( ; it != pntList.end(); ++it )
1056     glVertex2f( (*it).x(), (*it).y() );
1057   glEnd();
1058 }
1059
1060 /*!
1061   Draws rectangle
1062   \param rect - instance of rectangle
1063   \param color - color of polygon
1064   \param pattern - pattern of line
1065   \param isStripe - enables line stipple
1066 */
1067 void GLViewer_Drawer::drawPolygon( GLViewer_Rect* rect, QColor color,
1068                                       GLushort pattern, bool isStripe )
1069 {
1070   float x1 = rect->left();
1071   float x2 = rect->right();
1072   float y1 = rect->bottom();
1073   float y2 = rect->top();
1074   glColor3f( ( GLfloat )color.red() / 255,
1075     ( GLfloat )color.green() / 255,
1076     ( GLfloat )color.blue() / 255 );
1077
1078   if ( isStripe )
1079   {
1080     glEnable( GL_LINE_STIPPLE );
1081     glLineStipple( 1, pattern );
1082   }
1083   glBegin( GL_POLYGON );
1084
1085   glVertex2f( x1, y1 );
1086   glVertex2f( x1, y2 );
1087   glVertex2f( x2, y2 );
1088   glVertex2f( x2, y1 );
1089
1090   glEnd();
1091   glDisable( GL_LINE_STIPPLE );
1092 }
1093
1094 GLubyte rasterVertex[5] = { 0x70, 0xf8, 0xf8, 0xf8, 0x70 };
1095
1096 /*!
1097   Draws vertex
1098   \param x - x position
1099   \param y - y position
1100   \param color - color of vertex
1101 */
1102 void GLViewer_Drawer::drawVertex( GLfloat x, GLfloat y, QColor color )
1103 {
1104   glColor3f( ( GLfloat )color.red() / 255, ( GLfloat )color.green() / 255, ( GLfloat )color.blue() / 255 );
1105   glRasterPos2f( x, y );
1106   glBitmap( 5, 5, 2, 2, 0, 0, rasterVertex );
1107 }
1108
1109 GLubyte rasterCross[7] =  { 0x82, 0x44, 0x28, 0x10, 0x28, 0x44, 0x82 };
1110
1111 /*!
1112   Draws cross
1113   \param x - x position
1114   \param y - y position
1115   \param color - color of cross
1116 */
1117 void GLViewer_Drawer::drawCross( GLfloat x, GLfloat y, QColor color )
1118 {
1119   glColor3f( ( GLfloat )color.red() / 255, ( GLfloat )color.green() / 255, ( GLfloat )color.blue() / 255 );
1120   glRasterPos2f( x, y );
1121   glBitmap( 7, 7, 3, 3, 0, 0, rasterCross );
1122 }
1123
1124 /*!
1125   Draws arrow
1126   \param red, green, blue - components of color
1127   \param lineWidth - width of line
1128   \param staff - 
1129   \param length - length of arrow
1130   \param width - width of arrow
1131   \param x - x position
1132   \param y - y position
1133   \param angle - angle of arrow
1134   \param filled - drawn as filled
1135 */
1136 void GLViewer_Drawer::drawArrow( const GLfloat red, const GLfloat green, const GLfloat blue,
1137                                  GLfloat lineWidth,
1138                                  GLfloat staff, GLfloat length, GLfloat width,
1139                                  GLfloat x, GLfloat y, GLfloat angle, GLboolean filled )
1140 {
1141   GLfloat vx1 = x;
1142   GLfloat vy1 = y + staff + length;
1143   GLfloat vx2 = vx1 - width / 2;
1144   GLfloat vy2 = vy1 - length;
1145   GLfloat vx3 = vx1 + width / 2;
1146   GLfloat vy3 = vy1 - length;
1147
1148   gp_Pnt2d p0( x, y );
1149   gp_Pnt2d p1( vx1, vy1 );
1150   gp_Pnt2d p2( vx2, vy2 );
1151   gp_Pnt2d p3( vx3, vy3 );
1152
1153   p1.Rotate( p0, angle );
1154   p2.Rotate( p0, angle );
1155   p3.Rotate( p0, angle );
1156   
1157   vx1 = p1.X(); vy1 = p1.Y();
1158   vx2 = p2.X(); vy2 = p2.Y();
1159   vx3 = p3.X(); vy3 = p3.Y();
1160
1161   glColor3f( red, green, blue );
1162   glLineWidth( lineWidth );
1163
1164   glBegin( GL_LINES );
1165   glVertex2f( x, y );
1166   glVertex2f( vx1, vy1 );
1167   glEnd();
1168
1169   filled = true;
1170   if( !filled )
1171   {
1172     glBegin( GL_LINES );
1173     glVertex2f( vx1, vy1 );
1174     glVertex2f( vx2, vy2 );
1175     glVertex2f( vx1, vy1 );
1176     glVertex2f( vx3, vy3 );
1177     glEnd();
1178   }
1179   else
1180   {
1181     glBegin( GL_POLYGON );
1182     glVertex2f( vx1, vy1 );
1183     glVertex2f( vx2, vy2 );
1184     glVertex2f( vx3, vy3 );
1185     glEnd();
1186   }
1187 }