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