]> SALOME platform Git repositories - modules/gui.git/blob - src/GLViewer/GLViewer_Drawer.cxx
Salome HOME
e983b8a08db1ecc3d5710bf1605e527f9e84421b
[modules/gui.git] / src / GLViewer / GLViewer_Drawer.cxx
1 // File:      GLViewer_Drawer.cxx
2 // Created:   November, 2004
3 // Author:    OCC team
4 // Copyright (C) CEA 2004
5
6 //#include <GLViewerAfx.h>
7 #include "GLViewer_Drawer.h"
8 #include "GLViewer_Object.h"
9 #include "GLViewer_Text.h"
10 #include "GLViewer_ViewFrame.h"
11 #include "GLViewer_ViewPort2d.h"
12
13 #ifndef WIN32
14 #include <GL/glx.h>
15 #endif
16
17 #include <qimage.h>
18 #include <qpainter.h>
19
20 static int FirstSymbolNumber = 32;
21 static int LastSymbolNumber = 127;
22
23 QMap<GLViewer_TexFindId,GLViewer_TexIdStored> GLViewer_TexFont::TexFontBase; 
24
25 #define TEXT_GAP    5
26
27 GLboolean TFLoaded = GL_FALSE;
28
29 GLdouble        modelMatrix[16], projMatrix[16];
30 GLint           viewport[4];
31 GLdouble        winx, winy, winz;
32 GLint           status;
33
34 GLViewer_TexFont*  staticGlFont;
35
36
37 /***************************************************************************
38 **  Class:   GLViewer_TexFont
39 **  Descr:   Texture Font for GLViewer_Object
40 **  Module:  GLViewer
41 **  Created: UI team, 01.10.01
42 ****************************************************************************/
43 GLViewer_TexFont::GLViewer_TexFont()
44 {
45     myQFont = QFont::defaultFont();
46     QFontMetrics aFM( myQFont );        
47     myWidths = new int[LastSymbolNumber - FirstSymbolNumber+1];
48     myPositions = new int[LastSymbolNumber - FirstSymbolNumber+1];
49     mySeparator = 2;
50     for( int k = FirstSymbolNumber, aWidth = 0; k <= LastSymbolNumber; k++ )
51     {
52         myWidths[ k - FirstSymbolNumber ] = aFM.width( k );
53         myPositions[ k - FirstSymbolNumber ] = aWidth;
54         aWidth += myWidths[ k - FirstSymbolNumber ] + 2;//mySeparator;
55     }
56
57     myTexFontWidth = 0;
58     myTexFontHeight = 0;        
59 }
60
61 GLViewer_TexFont::GLViewer_TexFont( QFont* theFont, int theSeparator )
62 {
63     myQFont = *theFont;
64     QFontMetrics aFM( myQFont );        
65     myWidths = new int[LastSymbolNumber - FirstSymbolNumber+1];
66     myPositions = new int[LastSymbolNumber - FirstSymbolNumber+1];
67     mySeparator = theSeparator;
68     for( int k = FirstSymbolNumber, aWidth = 0; k <= LastSymbolNumber; k++ )
69     {
70         myWidths[ k - FirstSymbolNumber ] = aFM.width( k );
71         myPositions[ k - FirstSymbolNumber ] = aWidth;
72         aWidth += myWidths[ k - FirstSymbolNumber ] + 2;//mySeparator;
73     }
74
75     myTexFontWidth = 0;
76     myTexFontHeight = 0;
77     
78 }
79
80 GLViewer_TexFont::~GLViewer_TexFont()
81 {
82     delete[] myWidths;
83     delete[] myPositions;
84 }   
85
86 void GLViewer_TexFont::generateTexture()
87 {
88     QFontMetrics aFM( myQFont );
89
90     GLViewer_TexFindId aFindFont;
91     aFindFont.myFontString = myQFont.toString();
92     aFindFont.myViewPortId = (int)QGLContext::currentContext();
93         
94     if( TexFontBase.contains( aFindFont ) )
95     {
96         GLViewer_TexIdStored aTexture = TexFontBase[ aFindFont ];
97         myTexFont = aTexture.myTexFontId;
98         myTexFontWidth = aTexture.myTexFontWidth;
99         myTexFontHeight = aTexture.myTexFontHeight;
100     }    
101     else    
102     {
103         QString aStr;
104         int pixelsWidth = 0;
105         int pixelsHight = aFM.height();
106         myTexFontWidth = 64;
107         myTexFontHeight = 64;
108     
109         pixelsWidth = myWidths[LastSymbolNumber - FirstSymbolNumber] + 
110                       myPositions[LastSymbolNumber - FirstSymbolNumber];
111
112         while( myTexFontWidth < pixelsWidth )
113             myTexFontWidth = myTexFontWidth * 2;
114         while( myTexFontHeight < pixelsHight )
115             myTexFontHeight = myTexFontHeight * 2;
116
117         QPixmap aPixmap( myTexFontWidth, myTexFontHeight );
118         aPixmap.fill( QColor( 0, 0, 0) );
119         QPainter aPainter( &aPixmap );
120         aPainter.setFont( myQFont );
121         for( int l = 0/*, gap = 0*/; l < LastSymbolNumber - FirstSymbolNumber; l++  )
122         {
123             QString aLetter;
124             aLetter += (char)(FirstSymbolNumber + l);
125             aPainter.setPen( QColor( 255,255,255) );
126             aPainter.drawText ( myPositions[l], pixelsHight, aLetter );
127         }
128     
129         QImage aImage = aPixmap.convertToImage();
130         char* pixels = new char[myTexFontWidth * myTexFontHeight * 2];
131
132         for( int i = 0; i < myTexFontHeight; i++ )
133         {            
134             for( int j = 0; j < myTexFontWidth;  j++ )
135             {
136                 int aRed = qRed( aImage.pixel( j, myTexFontHeight - i - 1 ) );
137                 int aGreen = qGreen( aImage.pixel( j, myTexFontHeight - i - 1 ) );
138                 int aBlue = qBlue( aImage.pixel( j, myTexFontHeight - i - 1 ) );
139           
140                 if( aRed != 0 || aGreen != 0 || aBlue != 0 )
141                 {
142                     pixels[i * myTexFontWidth * 2 + j * 2] = (GLubyte)( (aRed + aGreen + aBlue)/3 );
143                     pixels[i * myTexFontWidth * 2 + j * 2 + 1]= (GLubyte) 255;
144                 }
145                 else
146                 {
147                     pixels[i * myTexFontWidth * 2 + j * 2] = (GLubyte) 0;
148                     pixels[i * myTexFontWidth * 2 + j * 2 + 1]= (GLubyte) 0;
149                 }                
150             }
151         }
152
153         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
154         glGenTextures(1, &myTexFont);
155         glBindTexture(GL_TEXTURE_2D, myTexFont);  
156         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
157         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
158         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
159         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
160         glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
161         glTexImage2D(GL_TEXTURE_2D, 0, 2, myTexFontWidth,
162             myTexFontHeight, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, pixels);
163     
164         delete[] pixels;
165         
166         GLViewer_TexIdStored aTexture;
167         aTexture.myTexFontId = myTexFont;
168         aTexture.myTexFontWidth = myTexFontWidth;
169         aTexture.myTexFontHeight = myTexFontHeight;
170
171         TexFontBase.insert( aFindFont, aTexture );
172     }
173 }
174
175 void GLViewer_TexFont::drawString( QString theStr, GLdouble theX , GLdouble theY )
176 {
177     glEnable(GL_TEXTURE_2D);
178     glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
179     glPixelTransferi(GL_MAP_COLOR, 0);
180     glAlphaFunc(GL_GEQUAL, 0.5F);
181     glEnable(GL_ALPHA_TEST);
182     glBindTexture(GL_TEXTURE_2D, myTexFont);
183     glBegin(GL_QUADS);
184
185     QFontMetrics aFM( myQFont );
186     int pixelsHeight = aFM.height();
187
188     theY = theY - myTexFontHeight + pixelsHeight;
189
190     for( int i = 0, aGap = 0; i < theStr.length(); i++ )
191     {
192         char aLetter = theStr.data()[i];
193         int aLettIndex = (int)aLetter - FirstSymbolNumber;
194
195         float aLettBegin = (float)myPositions[aLettIndex];
196         float aLettEnd = aLettBegin + myWidths[aLettIndex]-1;
197
198         aLettBegin = aLettBegin / myTexFontWidth;
199         aLettEnd = aLettEnd / myTexFontWidth;
200
201         glTexCoord2f( aLettBegin, 0.0 ); glVertex3f( theX + aGap, theY, 1.0 );
202         glTexCoord2f( aLettBegin, 1.0 ); glVertex3f( theX + aGap, theY + myTexFontHeight, 1.0 );
203         glTexCoord2f( aLettEnd, 1.0 ); glVertex3f( theX + aGap + myWidths[aLettIndex]-1, theY + myTexFontHeight, 1.0 );
204         glTexCoord2f( aLettEnd, 0.0 ); glVertex3f( theX + aGap + myWidths[aLettIndex]-1, theY, 1.0 );
205
206         aGap += myWidths[aLettIndex]-1 + mySeparator;
207     }
208
209     glEnd();
210     glDisable(GL_ALPHA_TEST);
211     glDisable(GL_TEXTURE_2D);
212 }
213
214 int GLViewer_TexFont::getStringWidth( QString theStr )
215 {
216     int aWidth = 0;
217     for( int i = 0; i < theStr.length(); i ++ )
218     {
219         char aLetter = theStr.data()[i];
220         int aLettIndex = (int)aLetter - FirstSymbolNumber;
221         aWidth += myWidths[aLettIndex] + mySeparator;
222     }
223
224     return aWidth;
225 }
226
227 int GLViewer_TexFont::getStringHeight()
228 {
229     QFontMetrics aFM( myQFont );
230     return aFM.height();
231 }
232
233 void GLViewer_Drawer::destroyAllTextures()
234 {
235     QMap<GLViewer_TexFindId,GLViewer_TexIdStored>::Iterator anIt= GLViewer_TexFont::TexFontBase.begin();
236     QMap<GLViewer_TexFindId,GLViewer_TexIdStored>::Iterator anEndIt= GLViewer_TexFont::TexFontBase.end();
237
238     for( ; anIt != anEndIt; anIt++ )
239         glDeleteTextures( 1, &(anIt.data().myTexFontId) );
240 }
241
242 static GLuint displayListBase( QFont* theFont )
243 {
244   GLuint aList = 0;
245   static QMap<GLViewer_TexFindId, GLuint> fontCache;
246   GLViewer_TexFindId aFindFont;
247   aFindFont.myFontString = theFont->toString();
248
249 #ifdef WIN32
250   HGLRC ctx = ::wglGetCurrentContext();
251   if ( !ctx )
252     return aList;  
253   
254   aFindFont.myViewPortId = (int)ctx;
255
256   if ( fontCache.contains( aFindFont ) )
257     aList = fontCache[aFindFont];
258   else
259   {
260     GLuint listBase = 0;
261     QMap<GLViewer_TexFindId, GLuint>::iterator it = fontCache.begin();
262     for ( ; it != fontCache.end(); ++it )
263     {
264       if ( it.key().myViewPortId == (int)ctx && it.data() > listBase )
265         listBase = it.data();
266     }
267     listBase += 256;
268
269     HDC glHdc = ::wglGetCurrentDC();
270     ::SelectObject( glHdc, theFont->handle() );
271     if ( !::wglUseFontBitmaps( glHdc, 0, 256, listBase ) )
272       listBase = 0;
273     aList = listBase;
274     fontCache[aFindFont] = aList;
275   }
276 #else //X Window
277   Display* aDisp = glXGetCurrentDisplay();
278   if( !aDisp )
279   {
280     printf( "Can't find current dislay\n" );
281     return aList;
282   }
283   
284   GLXContext aCont = glXGetCurrentContext();
285   if( !aCont )
286   {
287     printf( "Can't find current context\n" );
288     return aList;
289   }
290
291   aFindFont.myViewPortId = (int)aCont;
292
293   if ( fontCache.contains( aFindFont ) )
294     aList = fontCache[aFindFont];
295   else
296   {
297     GLuint listBase = 0;
298     QMap<GLViewer_TexFindId, GLuint>::iterator it = fontCache.begin();
299     for ( ; it != fontCache.end(); ++it )
300     {
301       if ( it.key().myViewPortId == (int)aCont && it.data() > listBase )
302         listBase = it.data();
303     }
304     listBase += 256;
305
306     glXUseXFont( (Font)(theFont->handle()), 0, 256, listBase );
307
308     aList = listBase;
309     fontCache[aFindFont] = aList;
310   }
311
312 #endif
313
314   return aList;
315 }
316
317 /***************************************************************************
318 **  Class:   GLViewer_Drawer
319 **  Descr:   Drawer for GLViewer_Object
320 **  Module:  GLViewer
321 **  Created: UI team, 01.10.01
322 ****************************************************************************/
323 GLViewer_Drawer::GLViewer_Drawer()
324 {
325   myXScale = myYScale = 0.0;
326   myObjects.clear();
327   myTextList = 0/*-1*/;
328   myObjectType = "GLViewer_Object";
329   myPriority = 0;
330 }
331
332 GLViewer_Drawer::~GLViewer_Drawer()
333 {
334   myObjects.clear();
335   glDeleteLists( myTextList, 1 );
336 }
337
338 GLuint GLViewer_Drawer::loadTexture( const QString& fileName )
339 {
340     QImage buf;
341     if ( fileName.isEmpty() || !buf.load( fileName ) )
342         return 0;
343
344     int w = buf.width();
345     int h = buf.height();
346
347     int size = 16;
348     while( size < w || size < h )
349         size = size * 2;
350
351     GLuint texture;
352     GLubyte* pixels = new GLubyte[ size * size * 4 ];
353
354     for( int i = 0; i < size; i++ )
355     {            
356         for( int j = 0; j < size; j++ )
357         {
358             GLubyte r, g, b;
359             if( j < w && i < h )
360             {
361                 QRgb pixel = buf.pixel( j, h - i - 1 );
362                 r = (GLubyte)qRed( pixel );
363                 g = (GLubyte)qGreen( pixel );
364                 b = (GLubyte)qBlue( pixel );
365             }
366             else
367             {
368                 r = (GLubyte)255;
369                 g = (GLubyte)255;
370                 b = (GLubyte)255;
371             }
372
373             int index = 4 * ( i * size + j );
374             pixels[ index ] = r;
375             pixels[ index + 1 ] = g;
376             pixels[ index + 2 ] = b;
377
378             if( r == (GLubyte)255 && g == (GLubyte)255 && b == (GLubyte)255 )
379                 pixels[ index + 3 ] = (GLubyte)0;
380             else
381                 pixels[ index + 3 ] = (GLubyte)255;
382         }
383     }
384
385     //initialize texture
386     glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
387     glGenTextures( 1, &texture );
388     glBindTexture( GL_TEXTURE_2D, texture );
389     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
390     glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
391     glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, size, size, 0,
392                   GL_RGBA, GL_UNSIGNED_BYTE, pixels );
393
394     delete[] pixels;
395
396     return texture;
397 }
398
399 void GLViewer_Drawer::drawTexture( GLuint texture, GLint size, GLfloat x, GLfloat y )
400 {
401     float xScale = myXScale;
402     float yScale = myYScale;
403
404     glColor4f( 1.0, 1.0, 1.0, 1.0 );
405
406     glEnable( GL_TEXTURE_2D );
407     glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE );
408     glAlphaFunc( GL_GREATER, 0.95F );
409     glEnable( GL_ALPHA_TEST );
410     
411     glBindTexture( GL_TEXTURE_2D, texture );
412     glBegin( GL_QUADS );
413
414     glTexCoord2f( 0.0, 0.0 );
415     glVertex3f( x-size/2./xScale, y-size/2./yScale, 0.0 );
416
417     glTexCoord2f( 0.0, 1.0 );
418     glVertex3f( x-size/2./xScale, y+size/2./yScale, 0.0 );
419
420     glTexCoord2f( 1.0, 1.0 );
421     glVertex3f( x+size/2./xScale, y+size/2./yScale, 0.0 );
422
423     glTexCoord2f( 1.0, 0.0 );
424     glVertex3f( x+size/2./xScale, y-size/2./yScale, 0.0 );
425     
426     glEnd();
427     glFlush();
428
429     glDisable( GL_ALPHA_TEST );
430     glDisable( GL_TEXTURE_2D );
431 }
432
433 void GLViewer_Drawer::drawText( const QString& text, GLfloat xPos, GLfloat yPos,
434                                 const QColor& color, QFont* theFont, int theSeparator, DisplayTextFormat theFormat )
435 {
436   if( theFormat == DTF_TEXTURE )
437   {
438     GLViewer_TexFont aTexFont( theFont, theSeparator );
439     aTexFont.generateTexture();
440
441     glGetIntegerv (GL_VIEWPORT, viewport);
442     glGetDoublev (GL_MODELVIEW_MATRIX, modelMatrix);
443     glGetDoublev (GL_PROJECTION_MATRIX, projMatrix);
444     status = gluProject (xPos, yPos, 0, modelMatrix, projMatrix, viewport, &winx, &winy, &winz);
445
446     glPushAttrib( GL_TRANSFORM_BIT | GL_VIEWPORT_BIT | GL_LIST_BIT );
447     glMatrixMode(GL_PROJECTION);
448     glPushMatrix();
449     glLoadIdentity();
450     glOrtho(0,viewport[2],0,viewport[3],-100,100);
451     glMatrixMode(GL_MODELVIEW);
452     glPushMatrix();
453     glLoadIdentity();
454
455     glColor3f( ( GLfloat )color.red() / 255, 
456                ( GLfloat )color.green() / 255, 
457                ( GLfloat )color.blue() / 255 );
458
459     aTexFont.drawString( text, winx, winy );
460
461     glPopMatrix();
462     glMatrixMode(GL_PROJECTION);
463     glPopMatrix();
464     glPopAttrib();
465   }
466   else if( theFormat == DTF_BITMAP )
467   {
468     glColor3f( ( GLfloat )color.red() / 255, 
469                ( GLfloat )color.green() / 255, 
470                ( GLfloat )color.blue() / 255 );
471     glRasterPos2f( xPos, yPos );
472     glListBase( displayListBase( theFont ) );
473     glCallLists( text.length(), GL_UNSIGNED_BYTE, text.local8Bit().data() );
474   }
475 }
476
477 void GLViewer_Drawer::drawText( GLViewer_Object* theObject )
478 {
479   if( !theObject )
480     return;
481
482   GLViewer_Text* aText = theObject->getGLText();
483   if( !aText )
484     return;
485
486   GLfloat aPosX, aPosY;
487   aText->getPosition( aPosX, aPosY );
488   // get temporary copy of font
489   QFont aTmpVarFont = aText->getFont();
490   drawText( aText->getText(), aPosX, aPosY, aText->getColor(), &aTmpVarFont, aText->getSeparator(), aText->getDisplayTextFormat() );
491 }
492
493 void GLViewer_Drawer::drawGLText( QString text, float x, float y,
494                                   int hPosition, int vPosition, QColor color, bool smallFont )
495 {
496   QFont aFont( "Arial", 10, QFont::Bold );
497   if( smallFont )
498     aFont.setPointSize( 8 );
499
500   QFontMetrics aFontMetrics( aFont );
501   float width = aFontMetrics.width( text ) / myXScale;
502   float height = aFontMetrics.height() / myXScale;
503   float gap = 5 / myXScale;
504
505   switch( hPosition )
506   {
507       case GLText_Left   : x -= ( gap + width ); break;
508       case GLText_Center : x -= width / 2; break;
509       case GLText_Right  : x += gap; break;
510       default : break;
511   }
512
513   switch( vPosition )
514   {
515       case GLText_Top    : y += height * 0.5; break;
516       case GLText_Center : y -= height * 0.5; break;
517       case GLText_Bottom : y -= height * 1.5; break;
518       default : break;
519   }
520
521   drawText( text, x, y, color, &aFont, 2 );
522 }
523
524 void GLViewer_Drawer::drawRectangle( GLViewer_Rect* rect, QColor color )
525 {
526   if( !rect )
527     return;
528
529   float x1 = rect->left();
530   float x2 = rect->right();
531   float y1 = rect->bottom();
532   float y2 = rect->top();
533   
534   glColor3f( ( GLfloat )color.red() / 255,
535     ( GLfloat )color.green() / 255,
536     ( GLfloat )color.blue() / 255 );
537   glLineWidth( 1.0 );
538   
539   glBegin( GL_LINE_LOOP );
540   glVertex2f( x1, y1 );
541   glVertex2f( x1, y2 );
542   glVertex2f( x2, y2 );
543   glVertex2f( x2, y1 );
544   glEnd();
545 }
546
547 bool GLViewer_Drawer::translateToHPGL( QFile& hFile, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aHPGLCS )
548 {
549     bool result = true;
550     for( int i=0, n=myObjects.count(); i<n; i++ ) 
551         result &= myObjects[i]->translateToHPGL( hFile, aViewerCS, aHPGLCS );
552     return result;
553 }
554
555 bool GLViewer_Drawer::translateToPS( QFile& hFile, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aPSCS )
556 {
557     bool result = true;
558     for( int i=0, n=myObjects.count(); i<n; i++ ) 
559         result &= myObjects[i]->translateToPS( hFile, aViewerCS, aPSCS );
560     return result;
561 }
562
563 #ifdef WIN32
564 bool GLViewer_Drawer::translateToEMF( HDC hDC, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aEMFCS )
565 {
566     bool result = true;
567     for( int i=0, n=myObjects.count(); i<n; i++ ) 
568         result &= myObjects[i]->translateToEMF( hDC, aViewerCS, aEMFCS );
569     return result;
570 }
571 #endif