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