Salome HOME
Merge branch 'V7_dev'
[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  #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
402     ::SelectObject( glHdc, theFont->handle() );
403  #endif
404     if ( !::wglUseFontBitmaps( glHdc, 0, 256, listBase ) )
405       listBase = 0;
406     aList = listBase;
407     GLViewer_TexFont::BitmapFontCache[aFindFont] = aList;
408   }
409 #else //X Window
410   Display* aDisp = glXGetCurrentDisplay();
411   if( !aDisp )
412   {
413 #ifdef _DEBUG_
414     printf( "Can't find current dislay\n" );
415 #endif
416     return aList;
417   }
418   
419   GLXContext aCont = glXGetCurrentContext();
420   if( !aCont )
421   {
422 #ifdef _DEBUG_
423     printf( "Can't find current context\n" );
424 #endif
425     return aList;
426   }
427
428   aFindFont.myViewPortId = size_t(aCont);
429
430   if ( GLViewer_TexFont::BitmapFontCache.contains( aFindFont ) )
431     aList = GLViewer_TexFont::BitmapFontCache[aFindFont];
432   else
433   {
434     GLuint listBase = 0;
435     QMap<GLViewer_TexFindId, GLuint>::iterator it = GLViewer_TexFont::BitmapFontCache.begin();
436     for ( ; it != GLViewer_TexFont::BitmapFontCache.end(); ++it )
437     {
438       if ( it.key().myViewPortId == size_t(aCont) && it.value() > listBase )
439         listBase = it.value();
440     }
441     listBase += 256;
442     
443     //glXUseXFont( (Font)(theFont->handle()), 0, 256, listBase );
444     int aFontCont = 0;
445     QString aFontDef = theFont->toString();
446     char** xFontList = XListFonts( aDisp, aFontDef.toLatin1()/*aFindFont.myFontString.data()*/, 1, &aFontCont  );
447 // TODO (QT5 PORTING) Below is a temporary solution, to allow compiling with Qt 5
448 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
449     if( !theFont->handle() )
450     {
451 #endif
452 #ifdef _DEBUG_
453       printf( "Can't load font %s. loading default font....\n", aFontDef.toLatin1().data()/*aFindFont.myFontString.data()*/ );
454 #endif
455       QString aFontMask ("-*-*-*-r-*-*-");
456       aFontMask += aFontDef/*aFindFont.myFontString*/.section( ',', 1, 1 );
457 #ifdef _DEBUG_
458       printf( "Height of Default font: %s\n", aFontDef/*aFindFont.myFontString*/.section( ',', 1, 1 ).data() );
459 #endif
460       aFontMask += "-*-*-*-m-*-*-*";
461       xFontList = XListFonts( aDisp, aFontMask.toLatin1().constData()/*"-*-*-*-r-*-*-12-*-*-*-m-*-*-*"*/, 1, &aFontCont  );
462       if( aFontCont == 0 )
463       {
464 #ifdef _DEBUG_
465         printf( "Can't load default font\n" );
466 #endif
467         return 0;
468       }
469       glXUseXFont( (Font)(XLoadFont( aDisp,xFontList[0] )), 0, 256, listBase );
470 #if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
471     }
472     else
473       glXUseXFont( (Font)(theFont->handle()), 0, 256, listBase );
474 #endif
475     aList = listBase;
476     GLViewer_TexFont::BitmapFontCache[aFindFont] = aList;
477   }
478
479 #endif
480
481   return aList;
482 }
483
484 /*!
485   Default constructor
486 */
487 GLViewer_Drawer::GLViewer_Drawer()
488 : myFont( "Helvetica", 10, QFont::Bold )
489 {
490   myXScale = myYScale = 0.0;
491   myObjects.clear();
492   myTextList = 0/*-1*/;
493   myObjectType = "GLViewer_Object";
494   myPriority = 0;
495   myTextFormat = DTF_BITMAP;
496   myTextScale = 0.125;
497 }
498
499 /*!
500   Destructor
501 */
502 GLViewer_Drawer::~GLViewer_Drawer()
503 {
504   myObjects.clear();
505   glDeleteLists( myTextList, 1 );
506 }
507
508 /*!
509   Clears all generated textures
510 */
511 void GLViewer_Drawer::destroyAllTextures()
512 {
513     QMap<GLViewer_TexFindId,GLViewer_TexIdStored>::Iterator anIt= GLViewer_TexFont::TexFontBase.begin();
514     QMap<GLViewer_TexFindId,GLViewer_TexIdStored>::Iterator anEndIt= GLViewer_TexFont::TexFontBase.end();
515
516     for( ; anIt != anEndIt; anIt++ )
517         glDeleteTextures( 1, &(anIt.value().myTexFontId) );
518 }
519
520 /*!
521   Enables and disables antialiasing in Open GL (for points, lines and polygons).
522   \param on - if it is true, antialiasing is enabled
523 */
524 void GLViewer_Drawer::setAntialiasing(const bool on)
525 {
526         if (on)
527         {
528     glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
529     glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
530
531                 glEnable(GL_POINT_SMOOTH);
532                 glEnable(GL_LINE_SMOOTH);
533                 glEnable(GL_POLYGON_SMOOTH);
534                 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); 
535                 glEnable (GL_BLEND);
536         }
537         else
538         {
539                 glDisable(GL_POINT_SMOOTH);
540                 glDisable(GL_LINE_SMOOTH);
541                 glDisable(GL_POLYGON_SMOOTH);
542                 glBlendFunc (GL_ONE, GL_ZERO);
543                 glDisable (GL_BLEND);
544         }
545 }
546
547 /*! Loads texture from file
548   \param fileName - the name of texture file
549   \param x_size   - the horizontal size of picture ( less or equal texture horizontal size )
550   \param y_size   - the vertical size of picture ( less or equal texture vertical size )
551   \param t_size   - the size of texture ( texture vertical size equals texture horizontal size )
552 */
553 GLuint GLViewer_Drawer::loadTexture( const QString& fileName,
554                                      GLint* x_size,
555                                      GLint* y_size,
556                                      GLint* t_size )
557 {
558     QImage buf;
559     if ( fileName.isEmpty() || !buf.load( fileName ) )
560         return 0;
561
562     int w = buf.width();
563     int h = buf.height();
564
565     int size = 16;
566     while( size < w || size < h )
567         size = size * 2;
568
569     GLuint texture;
570     GLubyte* pixels = new GLubyte[ size * size * 4 ];
571
572     for( int i = 0; i < size; i++ )
573     {            
574         for( int j = 0; j < size; j++ )
575         {
576             GLubyte r, g, b, a;
577             if( j < w && i < h )
578             {
579                 QRgb pixel = buf.pixel( j, h - i - 1 );
580                 r = (GLubyte)qRed( pixel );
581                 g = (GLubyte)qGreen( pixel );
582                 b = (GLubyte)qBlue( pixel );
583                 a = (GLubyte)qAlpha( pixel );
584             }
585             else
586             {
587                 r = (GLubyte)255;
588                 g = (GLubyte)255;
589                 b = (GLubyte)255;
590                 a = (GLubyte)255;
591             }
592
593             int index = 4 * ( i * size + j );
594             pixels[ index ] = r;
595             pixels[ index + 1 ] = g;
596             pixels[ index + 2 ] = b;
597             pixels[ index + 3 ] = a;
598         }
599     }
600
601     //initialize texture
602     glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
603     glGenTextures( 1, &texture );
604     glBindTexture( GL_TEXTURE_2D, texture );
605     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
606     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
607     glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, size, size, 0,
608                   GL_RGBA, GL_UNSIGNED_BYTE, pixels );
609
610     delete[] pixels;
611
612     if ( x_size )
613       *(x_size) = w;
614
615     if ( y_size )
616       *(y_size) = h;
617
618     if ( t_size )
619       *(t_size) = size;
620
621     return texture;
622 }
623
624 /*! Draw square texture
625    \param texture - the texture ID
626    \param size    - the size of square texture
627    \param x       - x coord
628    \param y       - y coord
629 */
630 void GLViewer_Drawer::drawTexture( GLuint texture, GLint size, GLfloat x, GLfloat y )
631 {
632     /*float xScale = myXScale;
633     float yScale = myYScale;
634
635     glColor4f( 1.0, 1.0, 1.0, 1.0 );
636
637     glEnable( GL_TEXTURE_2D );
638     glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
639     glAlphaFunc( GL_GREATER, 0.95F );
640     glEnable( GL_ALPHA_TEST );
641     
642     glBindTexture( GL_TEXTURE_2D, texture );
643     glBegin( GL_QUADS );
644
645     glTexCoord2f( 0.0, 0.0 );
646     glVertex3f( x-size/2./xScale, y-size/2./yScale, 0.0 );
647
648     glTexCoord2f( 0.0, 1.0 );
649     glVertex3f( x-size/2./xScale, y+size/2./yScale, 0.0 );
650
651     glTexCoord2f( 1.0, 1.0 );
652     glVertex3f( x+size/2./xScale, y+size/2./yScale, 0.0 );
653
654     glTexCoord2f( 1.0, 0.0 );
655     glVertex3f( x+size/2./xScale, y-size/2./yScale, 0.0 );
656     
657     glEnd();
658     glFlush();
659
660     glDisable( GL_ALPHA_TEST );
661     glDisable( GL_TEXTURE_2D );*/
662
663   drawTexture( texture, size, size, x, y );
664 }
665
666 /*! Draw texture
667    \param texture - the texture ID
668    \param x_size  - the horizontal size of texture
669    \param y_size  - the vertical size of texture
670    \param x       - x coord
671    \param y       - y coord
672 */
673 void GLViewer_Drawer::drawTexture( GLuint texture, GLint x_size, GLint y_size, GLfloat x, GLfloat y )
674 {
675     /*float xScale = myXScale;
676     float yScale = myYScale;
677
678     glColor4f( 1.0, 1.0, 1.0, 1.0 );
679
680     glEnable( GL_TEXTURE_2D );
681     glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
682     glAlphaFunc( GL_GREATER, 0.95F );
683     glEnable( GL_ALPHA_TEST );
684     
685     glBindTexture( GL_TEXTURE_2D, texture );
686     glBegin( GL_QUADS );
687
688     glTexCoord2f( 0.0, 0.0 );
689     glVertex3f( x-x_size/2./xScale, y-y_size/2./yScale, 0.0 );
690
691     glTexCoord2f( 0.0, 1.0 );
692     glVertex3f( x-x_size/2./xScale, y+y_size/2./yScale, 0.0 );
693
694     glTexCoord2f( 1.0, 1.0 );
695     glVertex3f( x+x_size/2./xScale, y+y_size/2./yScale, 0.0 );
696
697     glTexCoord2f( 1.0, 0.0 );
698     glVertex3f( x+x_size/2./xScale, y-y_size/2./yScale, 0.0 );
699     
700     glEnd();
701     glFlush();
702
703     glDisable( GL_ALPHA_TEST );
704     glDisable( GL_TEXTURE_2D );*/
705   drawTexturePart( texture, 1.0, 1.0, x_size, y_size, x, y );
706 }
707
708 /*! Draw texture part
709    \param texture - the texture ID
710    \param x_ratio - the horizontal ratio of texture part
711    \param y_ratio - the vertical ratio of texture part
712    \param x_size  - the horizontal size of texture
713    \param y_size  - the vertical size of texture
714    \param x       - x coord
715    \param y       - y coord
716    \param scale   - common scale factor ( if = 0, use drawer scales )
717 */
718 void GLViewer_Drawer::drawTexturePart( GLuint texture,
719                                        GLfloat x_ratio,
720                                        GLfloat y_ratio,
721                                        GLfloat x_size,
722                                        GLfloat y_size,
723                                        GLfloat x,
724                                        GLfloat y,
725                                        GLfloat scale )
726 {
727   if( !texture )
728     return;
729
730   float xScale = scale > 0. ? 1./scale : myXScale;
731   float yScale = scale > 0. ? 1./scale : myYScale;
732
733   glColor4f( 1.0, 1.0, 1.0, 1.0 );
734
735
736   glEnable( GL_TEXTURE_2D );
737   glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
738   bool hasAlpha = glIsEnabled( GL_ALPHA_TEST );
739   glDisable( GL_ALPHA_TEST );
740
741   glBindTexture( GL_TEXTURE_2D, texture );
742   glBegin( GL_QUADS );
743
744   glTexCoord2f( 0.0, 0.0 );
745   glVertex3f( x-x_size/2./xScale, y-y_size/2./yScale, 0.0 );
746
747   glTexCoord2f( 0.0, y_ratio );
748   glVertex3f( x-x_size/2./xScale, y+y_size/2./yScale, 0.0 );
749
750   glTexCoord2f( x_ratio, y_ratio );
751   glVertex3f( x+x_size/2./xScale, y+y_size/2./yScale, 0.0 );
752
753   glTexCoord2f( x_ratio, 0.0 );
754   glVertex3f( x+x_size/2./xScale, y-y_size/2./yScale, 0.0 );
755   
756   glEnd();
757   glFlush();
758
759   if ( hasAlpha )
760     glEnable( GL_ALPHA_TEST );
761
762   glDisable( GL_TEXTURE_2D );
763 }
764
765 /*!
766   Draw text
767   \param text - text to be drawn
768   \param xPos - x position
769   \param yPos - y position
770   \param color - color of text
771   \param theFont - font of text
772   \param theSeparator - letter separator
773   \param theFormat - text format (by default DTF_BITMAP)
774 */
775 void GLViewer_Drawer::drawText( const QString& text, GLfloat xPos, GLfloat yPos,
776                                 const QColor& color, QFont* theFont, int theSeparator, DisplayTextFormat theFormat )
777 {
778   glColor3f( ( GLfloat )color.red() / 255, 
779              ( GLfloat )color.green() / 255, 
780              ( GLfloat )color.blue() / 255 );
781
782   if( theFormat != DTF_BITMAP )
783   {
784     GLViewer_TexFont aTexFont( theFont, theSeparator, theFormat == DTF_TEXTURE_SCALABLE, GL_LINEAR );
785     // Font texture was not found or generated --> cannot draw text
786     if ( !aTexFont.generateTexture() )
787       return;
788
789     if ( theFormat == DTF_TEXTURE_SCALABLE )
790       aTexFont.drawString( text, xPos, yPos, textScale() );
791     else
792       aTexFont.drawString( text, xPos, yPos );
793   }
794   else
795   {
796     glRasterPos2f( xPos, yPos );
797     glListBase( displayListBase( theFont ) );
798     glCallLists( text.length(), GL_UNSIGNED_BYTE, text.toLocal8Bit().data() );
799   }
800 }
801
802 /*!
803   Draws object-text
804 */
805 void GLViewer_Drawer::drawText( GLViewer_Object* theObject )
806 {
807   if( !theObject )
808     return;
809
810   GLViewer_Text* aText = theObject->getGLText();
811   if( !aText )
812     return;
813
814   GLfloat aPosX, aPosY;
815   aText->getPosition( aPosX, aPosY );
816   // get temporary copy of font
817   QFont aTmpVarFont = aText->getFont();
818   drawText( aText->getText(), aPosX, aPosY, aText->getColor(), &aTmpVarFont, aText->getSeparator(), aText->getDisplayTextFormat() );
819 }
820
821 /*! Draw text
822    \param text      - the text string
823    \param x         - x coord
824    \param y         - y coord
825    \param hPosition - horizontal alignment
826    \param vPosition - vertical alignment
827    \param color     - text color
828    \param smallFont - font format
829 */
830 void GLViewer_Drawer::drawGLText( QString text, float x, float y,
831                                   int hPosition, int vPosition, QColor color, bool smallFont )
832 {
833   QFont aFont( myFont );
834   if( smallFont )
835     aFont.setPointSize( int(aFont.pointSize() * 0.8) );
836
837   GLfloat scale = textScale() > 0. ? textScale() : 1.;
838
839   QFontMetrics aFontMetrics( aFont );
840   float width  = myTextFormat == DTF_TEXTURE_SCALABLE ? aFontMetrics.width( text ) * scale : aFontMetrics.width( text ) / myXScale;
841   float height = myTextFormat == DTF_TEXTURE_SCALABLE ? aFontMetrics.height() * scale : aFontMetrics.height() / myYScale;
842   float gap = 5 / myXScale;
843
844   switch( hPosition )
845   {
846       case GLText_Left   : x -= ( gap + width ); break;
847       case GLText_Center : x -= width / 2; break;
848       case GLText_Right  : x += gap; break;
849       default : break;
850   }
851
852   switch( vPosition )
853   {
854       case GLText_Top    : y += height * 0.5; break;
855       case GLText_Center : y -= height * 0.5; break;
856       case GLText_Bottom : y -= height * 1.5; break;
857       default : break;
858   }
859
860   drawText( text, x, y, color, &aFont, 2, myTextFormat );
861 }
862
863 /*!
864   \return a rectangle of text (without viewer scale)
865 */
866 GLViewer_Rect GLViewer_Drawer::textRect( const QString& text ) const
867 {
868   GLfloat scale = textScale() > 0. ? textScale() : 1.;
869
870   QFontMetrics aFontMetrics( myFont );
871   float width  = myTextFormat == DTF_TEXTURE_SCALABLE ? aFontMetrics.width( text ) * scale : aFontMetrics.width( text );
872   float height = myTextFormat == DTF_TEXTURE_SCALABLE ? aFontMetrics.height() * scale : aFontMetrics.height();
873
874   return GLViewer_Rect( 0, width, height, 0 );
875 }
876
877 /*!
878   Draws rectangle
879   \param rect - instance of primitive
880   \param color - color of primitive
881 */
882 void GLViewer_Drawer::drawRectangle( GLViewer_Rect* rect, QColor color )
883 {
884   if( !rect )
885     return;
886
887   float x1 = rect->left();
888   float x2 = rect->right();
889   float y1 = rect->bottom();
890   float y2 = rect->top();
891   
892   glColor3f( ( GLfloat )color.red() / 255,
893     ( GLfloat )color.green() / 255,
894     ( GLfloat )color.blue() / 255 );
895   glLineWidth( 1.0 );
896   
897   glBegin( GL_LINE_LOOP );
898   glVertex2f( x1, y1 );
899   glVertex2f( x1, y2 );
900   glVertex2f( x2, y2 );
901   glVertex2f( x2, y1 );
902   glEnd();
903 }
904
905 /*!
906   Saves object to file with format of HPGL
907   \param hFile - file
908   \param aViewerCS - viewer co-ordinate system
909   \param aHPGLCS - paper co-ordinate system
910 */
911 bool GLViewer_Drawer::translateToHPGL( QFile& hFile, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aHPGLCS )
912 {
913     bool result = true;
914     for( int i=0, n=myObjects.count(); i<n; i++ ) 
915         result &= myObjects[i]->translateToHPGL( hFile, aViewerCS, aHPGLCS );
916     return result;
917 }
918
919 /*!
920   Saves object to file with format of PostScript
921   \param hFile - file
922   \param aViewerCS - viewer co-ordinate system
923   \param aPSCS - paper co-ordinate system
924 */
925 bool GLViewer_Drawer::translateToPS( QFile& hFile, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aPSCS )
926 {
927     bool result = true;
928     for( int i=0, n=myObjects.count(); i<n; i++ ) 
929         result &= myObjects[i]->translateToPS( hFile, aViewerCS, aPSCS );
930     return result;
931 }
932
933 #ifdef WIN32
934 /*!
935   Saves object to file with format of EMF
936   \param hFile - file
937   \param aViewerCS - viewer co-ordinate system
938   \param aEMFCS - paper co-ordinate system
939 */
940 bool GLViewer_Drawer::translateToEMF( HDC hDC, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aEMFCS )
941 {
942     bool result = true;
943     for( int i=0, n=myObjects.count(); i<n; i++ ) 
944         result &= myObjects[i]->translateToEMF( hDC, aViewerCS, aEMFCS );
945     return result;
946 }
947 #endif
948
949 /*!
950   Draws rectangle
951   \param rect - instance of primitive
952   \param lineWidth - width of line
953   \param gap - gap of rectangle
954   \param color - color of primitive
955   \param filled - if it is true, then rectangle will be drawn filled with color "fillingColor"
956   \param fillingColor - color of filling
957 */
958 void GLViewer_Drawer::drawRectangle( GLViewer_Rect* rect, GLfloat lineWidth, GLfloat gap,
959                                      QColor color, bool filled, QColor fillingColor )
960 {
961   if( !rect )
962     return;
963
964   float x1 = rect->left() - gap;
965   float x2 = rect->right() + gap;
966   float y1 = rect->bottom() - gap;
967   float y2 = rect->top() + gap;
968   
969   if( filled )
970   {
971     glColor3f( ( GLfloat )fillingColor.red() / 255,
972       ( GLfloat )fillingColor.green() / 255,
973       ( GLfloat )fillingColor.blue() / 255 );
974     glBegin( GL_POLYGON );
975     glVertex2f( x1, y1 );
976     glVertex2f( x1, y2 );
977     glVertex2f( x2, y2 );
978     glVertex2f( x2, y1 );
979     glEnd();
980   }
981
982   glColor3f( ( GLfloat )color.red() / 255,
983     ( GLfloat )color.green() / 255,
984     ( GLfloat )color.blue() / 255 );
985   glLineWidth( lineWidth );
986   
987   glBegin( GL_LINE_LOOP );
988   glVertex2f( x1, y1 );
989   glVertex2f( x1, y2 );
990   glVertex2f( x2, y2 );
991   glVertex2f( x2, y1 );
992   glEnd();
993 }
994
995 /*!
996   Draws contour
997   \param pntList - list of points
998   \param color - color of contour
999   \param lineWidth - width of line
1000 */
1001 void GLViewer_Drawer::drawContour( const GLViewer_PntList& pntList, QColor color, GLfloat lineWidth )
1002 {
1003   glColor3f( ( GLfloat )color.red() / 255,
1004     ( GLfloat )color.green() / 255,
1005     ( GLfloat )color.blue() / 255 );
1006   glLineWidth( lineWidth );
1007   
1008   glBegin( GL_LINES );
1009   QList<GLViewer_Pnt>::const_iterator it = pntList.begin();
1010   for( ; it != pntList.end(); ++it )
1011     glVertex2f( (*it).x(), (*it).y() );
1012   glEnd();
1013 }
1014
1015 /*!
1016   Draws rectangular contour
1017   \param rect - instance of rectangle
1018   \param color - color of primitive
1019   \param lineWidth - width of line
1020   \param pattern - pattern of line
1021   \param isStripe - enables line stipple
1022 */
1023 void GLViewer_Drawer::drawContour( GLViewer_Rect* rect, QColor color, GLfloat lineWidth,
1024                                    GLushort pattern, bool isStripe )
1025 {
1026   float x1 = rect->left();
1027   float x2 = rect->right();
1028   float y1 = rect->bottom();
1029   float y2 = rect->top();
1030   
1031   glColor3f( ( GLfloat )color.red() / 255,
1032     ( GLfloat )color.green() / 255,
1033     ( GLfloat )color.blue() / 255 );
1034   glLineWidth( lineWidth );
1035   
1036   if ( isStripe )
1037   {
1038     glEnable( GL_LINE_STIPPLE );
1039     glLineStipple( 1, pattern );
1040   }
1041
1042   glBegin( GL_LINE_LOOP );
1043
1044   glVertex2f( x1, y1 );
1045   glVertex2f( x1, y2 );
1046   glVertex2f( x2, y2 );
1047   glVertex2f( x2, y1 );
1048
1049   glEnd();
1050   glDisable( GL_LINE_STIPPLE );
1051 }
1052
1053 /*!
1054   Draws polygon
1055   \param pntList - list of points
1056   \param color - color of polygon
1057 */
1058 void GLViewer_Drawer::drawPolygon( const GLViewer_PntList& pntList, QColor color )
1059 {
1060   glColor3f( ( GLfloat )color.red() / 255,
1061     ( GLfloat )color.green() / 255,
1062     ( GLfloat )color.blue() / 255 );
1063   glBegin( GL_POLYGON );
1064   QList<GLViewer_Pnt>::const_iterator it = pntList.begin();
1065   for( ; it != pntList.end(); ++it )
1066     glVertex2f( (*it).x(), (*it).y() );
1067   glEnd();
1068 }
1069
1070 /*!
1071   Draws rectangle
1072   \param rect - instance of rectangle
1073   \param color - color of polygon
1074   \param pattern - pattern of line
1075   \param isStripe - enables line stipple
1076 */
1077 void GLViewer_Drawer::drawPolygon( GLViewer_Rect* rect, QColor color,
1078                                       GLushort pattern, bool isStripe )
1079 {
1080   float x1 = rect->left();
1081   float x2 = rect->right();
1082   float y1 = rect->bottom();
1083   float y2 = rect->top();
1084   glColor3f( ( GLfloat )color.red() / 255,
1085     ( GLfloat )color.green() / 255,
1086     ( GLfloat )color.blue() / 255 );
1087
1088   if ( isStripe )
1089   {
1090     glEnable( GL_LINE_STIPPLE );
1091     glLineStipple( 1, pattern );
1092   }
1093   glBegin( GL_POLYGON );
1094
1095   glVertex2f( x1, y1 );
1096   glVertex2f( x1, y2 );
1097   glVertex2f( x2, y2 );
1098   glVertex2f( x2, y1 );
1099
1100   glEnd();
1101   glDisable( GL_LINE_STIPPLE );
1102 }
1103
1104 GLubyte rasterVertex[5] = { 0x70, 0xf8, 0xf8, 0xf8, 0x70 };
1105
1106 /*!
1107   Draws vertex
1108   \param x - x position
1109   \param y - y position
1110   \param color - color of vertex
1111 */
1112 void GLViewer_Drawer::drawVertex( GLfloat x, GLfloat y, QColor color )
1113 {
1114   glColor3f( ( GLfloat )color.red() / 255, ( GLfloat )color.green() / 255, ( GLfloat )color.blue() / 255 );
1115   glRasterPos2f( x, y );
1116   glBitmap( 5, 5, 2, 2, 0, 0, rasterVertex );
1117 }
1118
1119 GLubyte rasterCross[7] =  { 0x82, 0x44, 0x28, 0x10, 0x28, 0x44, 0x82 };
1120
1121 /*!
1122   Draws cross
1123   \param x - x position
1124   \param y - y position
1125   \param color - color of cross
1126 */
1127 void GLViewer_Drawer::drawCross( GLfloat x, GLfloat y, QColor color )
1128 {
1129   glColor3f( ( GLfloat )color.red() / 255, ( GLfloat )color.green() / 255, ( GLfloat )color.blue() / 255 );
1130   glRasterPos2f( x, y );
1131   glBitmap( 7, 7, 3, 3, 0, 0, rasterCross );
1132 }
1133
1134 /*!
1135   Draws arrow
1136   \param red, green, blue - components of color
1137   \param lineWidth - width of line
1138   \param staff - 
1139   \param length - length of arrow
1140   \param width - width of arrow
1141   \param x - x position
1142   \param y - y position
1143   \param angle - angle of arrow
1144   \param filled - drawn as filled
1145 */
1146 void GLViewer_Drawer::drawArrow( const GLfloat red, const GLfloat green, const GLfloat blue,
1147                                  GLfloat lineWidth,
1148                                  GLfloat staff, GLfloat length, GLfloat width,
1149                                  GLfloat x, GLfloat y, GLfloat angle, GLboolean filled )
1150 {
1151   GLfloat vx1 = x;
1152   GLfloat vy1 = y + staff + length;
1153   GLfloat vx2 = vx1 - width / 2;
1154   GLfloat vy2 = vy1 - length;
1155   GLfloat vx3 = vx1 + width / 2;
1156   GLfloat vy3 = vy1 - length;
1157
1158   gp_Pnt2d p0( x, y );
1159   gp_Pnt2d p1( vx1, vy1 );
1160   gp_Pnt2d p2( vx2, vy2 );
1161   gp_Pnt2d p3( vx3, vy3 );
1162
1163   p1.Rotate( p0, angle );
1164   p2.Rotate( p0, angle );
1165   p3.Rotate( p0, angle );
1166   
1167   vx1 = p1.X(); vy1 = p1.Y();
1168   vx2 = p2.X(); vy2 = p2.Y();
1169   vx3 = p3.X(); vy3 = p3.Y();
1170
1171   glColor3f( red, green, blue );
1172   glLineWidth( lineWidth );
1173
1174   glBegin( GL_LINES );
1175   glVertex2f( x, y );
1176   glVertex2f( vx1, vy1 );
1177   glEnd();
1178
1179   filled = true;
1180   if( !filled )
1181   {
1182     glBegin( GL_LINES );
1183     glVertex2f( vx1, vy1 );
1184     glVertex2f( vx2, vy2 );
1185     glVertex2f( vx1, vy1 );
1186     glVertex2f( vx3, vy3 );
1187     glEnd();
1188   }
1189   else
1190   {
1191     glBegin( GL_POLYGON );
1192     glVertex2f( vx1, vy1 );
1193     glVertex2f( vx2, vy2 );
1194     glVertex2f( vx3, vy3 );
1195     glEnd();
1196   }
1197 }