1 // Copyright (C) 2005 OPEN CASCADE
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License.
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 // Lesser General Public License for more details.
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
17 // See http://www.opencascade.org/SALOME/ or email : webmaster.salome@opencascade.org
19 // Author : OPEN CASCADE
22 // File: GLViewer_Drawer.cxx
23 // Created: November, 2004
25 //#include <GLViewerAfx.h>
26 #include "GLViewer_Drawer.h"
27 #include "GLViewer_Object.h"
28 #include "GLViewer_Text.h"
29 #include "GLViewer_ViewFrame.h"
30 #include "GLViewer_ViewPort2d.h"
41 GLboolean TFLoaded = GL_FALSE;
43 GLdouble modelMatrix[16], projMatrix[16];
45 GLdouble winx, winy, winz;
48 GLViewer_TexFont* staticGlFont;
50 //================================================================
51 // Class : GLViewer_TexFont
53 //================================================================
54 //! code of first font symbol
55 static int FirstSymbolNumber = 32;
56 //! code of last font symbol
57 static int LastSymbolNumber = 127;
59 QMap<GLViewer_TexFindId,GLViewer_TexIdStored> GLViewer_TexFont::TexFontBase;
60 QMap<GLViewer_TexFindId,GLuint> GLViewer_TexFont::BitmapFontCache;
62 //=======================================================================
63 // Function: clearTextBases
65 //=======================================================================
66 void GLViewer_TexFont::clearTextBases()
68 //cout << "Clear font map" << endl;
70 BitmapFontCache.clear();
73 //======================================================================
74 // Function: GLViewer_TexFont
76 //=======================================================================
77 GLViewer_TexFont::GLViewer_TexFont()
79 myQFont = QFont::defaultFont();
80 QFontMetrics aFM( myQFont );
81 myWidths = new int[LastSymbolNumber - FirstSymbolNumber+1];
82 myPositions = new int[LastSymbolNumber - FirstSymbolNumber+1];
84 for( int k = FirstSymbolNumber, aWidth = 0; k <= LastSymbolNumber; k++ )
86 myWidths[ k - FirstSymbolNumber ] = aFM.width( k );
87 myPositions[ k - FirstSymbolNumber ] = aWidth;
88 aWidth += myWidths[ k - FirstSymbolNumber ] + 2;//mySeparator;
93 myIsResizeable = false;
94 //myMinMagFilter = GL_NEAREST;
95 myMinMagFilter = GL_LINEAR_ATTENUATION ;
98 //======================================================================
99 // Function: GLViewer_TexFont
101 //=======================================================================
102 GLViewer_TexFont::GLViewer_TexFont( QFont* theFont, int theSeparator, bool theIsResizeable, GLuint theMinMagFilter )
105 QFontMetrics aFM( myQFont );
106 myWidths = new int[LastSymbolNumber - FirstSymbolNumber+1];
107 myPositions = new int[LastSymbolNumber - FirstSymbolNumber+1];
108 mySeparator = theSeparator;
109 for( int k = FirstSymbolNumber, aWidth = 0; k <= LastSymbolNumber; k++ )
111 myWidths[ k - FirstSymbolNumber ] = aFM.width( k );
112 myPositions[ k - FirstSymbolNumber ] = aWidth;
113 aWidth += myWidths[ k - FirstSymbolNumber ] + 2;//mySeparator;
118 myIsResizeable = theIsResizeable;
119 myMinMagFilter = theMinMagFilter;
123 //======================================================================
124 // Function: ~GLViewer_TexFont
126 //=======================================================================
127 GLViewer_TexFont::~GLViewer_TexFont()
130 delete[] myPositions;
133 //======================================================================
134 // Function: generateTexture
136 //=======================================================================
137 void GLViewer_TexFont::generateTexture()
139 QFontMetrics aFM( myQFont );
141 GLViewer_TexFindId aFindFont;
142 aFindFont.myFontString = myQFont.toString();
143 aFindFont.myViewPortId = (int)QGLContext::currentContext();
145 if( TexFontBase.contains( aFindFont ) )
147 GLViewer_TexIdStored aTexture = TexFontBase[ aFindFont ];
148 myTexFont = aTexture.myTexFontId;
149 myTexFontWidth = aTexture.myTexFontWidth;
150 myTexFontHeight = aTexture.myTexFontHeight;
156 int pixelsHight = aFM.height();
158 myTexFontHeight = 64;
160 pixelsWidth = myWidths[LastSymbolNumber - FirstSymbolNumber] +
161 myPositions[LastSymbolNumber - FirstSymbolNumber];
163 while( myTexFontWidth < pixelsWidth )
164 myTexFontWidth = myTexFontWidth * 2;
165 while( myTexFontHeight < pixelsHight )
166 myTexFontHeight = myTexFontHeight * 2;
168 QPixmap aPixmap( myTexFontWidth, myTexFontHeight );
169 aPixmap.fill( QColor( 0, 0, 0) );
170 QPainter aPainter( &aPixmap );
171 aPainter.setFont( myQFont );
172 for( int l = 0/*, gap = 0*/; l < LastSymbolNumber - FirstSymbolNumber; l++ )
175 aLetter += (char)(FirstSymbolNumber + l);
176 aPainter.setPen( QColor( 255,255,255) );
177 aPainter.drawText ( myPositions[l], pixelsHight, aLetter );
180 QImage aImage = aPixmap.convertToImage();
181 char* pixels = new char[myTexFontWidth * myTexFontHeight * 2];
183 for( int i = 0; i < myTexFontHeight; i++ )
185 for( int j = 0; j < myTexFontWidth; j++ )
187 int aRed = qRed( aImage.pixel( j, myTexFontHeight - i - 1 ) );
188 int aGreen = qGreen( aImage.pixel( j, myTexFontHeight - i - 1 ) );
189 int aBlue = qBlue( aImage.pixel( j, myTexFontHeight - i - 1 ) );
191 if( aRed != 0 || aGreen != 0 || aBlue != 0 )
193 pixels[i * myTexFontWidth * 2 + j * 2] = (GLubyte)( (aRed + aGreen + aBlue)/3 );
194 pixels[i * myTexFontWidth * 2 + j * 2 + 1]= (GLubyte) 255;
198 pixels[i * myTexFontWidth * 2 + j * 2] = (GLubyte) 0;
199 pixels[i * myTexFontWidth * 2 + j * 2 + 1]= (GLubyte) 0;
204 glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
205 glGenTextures(1, &myTexFont);
206 glBindTexture(GL_TEXTURE_2D, myTexFont);
207 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
208 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
209 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, myMinMagFilter);
210 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, myMinMagFilter);
211 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
212 glTexImage2D(GL_TEXTURE_2D,
224 GLViewer_TexIdStored aTexture;
225 aTexture.myTexFontId = myTexFont;
226 aTexture.myTexFontWidth = myTexFontWidth;
227 aTexture.myTexFontHeight = myTexFontHeight;
229 TexFontBase.insert( aFindFont, aTexture );
233 //======================================================================
234 // Function: drawString
236 //=======================================================================
237 void GLViewer_TexFont::drawString( QString theStr, GLdouble theX , GLdouble theY )
239 double aXScale = 1., aYScale = 1.;
241 glPushAttrib( GL_ENABLE_BIT | GL_TEXTURE_BIT );
243 if ( !myIsResizeable )
245 glGetDoublev (GL_MODELVIEW_MATRIX, modelMatrix);
246 aXScale = modelMatrix[0];
247 aYScale = modelMatrix[5];
250 glEnable(GL_TEXTURE_2D);
252 glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
253 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
254 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
255 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, myMinMagFilter);
256 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, myMinMagFilter);
258 glPixelTransferi(GL_MAP_COLOR, 0);
260 glAlphaFunc(GL_GEQUAL, 0.05F);
261 glEnable(GL_ALPHA_TEST);
264 glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
266 glBindTexture(GL_TEXTURE_2D, myTexFont);
269 theY = theY - ( myTexFontHeight - QFontMetrics( myQFont ).height() ) / aYScale;
271 double aLettBegin, aLettEnd, aDY = ( myTexFontHeight - 1 ) / aYScale, aDX;
274 for( int i = 0; i < theStr.length(); i++ )
276 aLetter = theStr.data()[i];
277 aLettIndex = (int)aLetter - FirstSymbolNumber;
279 aLettBegin = (double)myPositions[aLettIndex] / ( (double)myTexFontWidth - 1. );
280 aLettEnd = aLettBegin + ( (double)myWidths[aLettIndex] - 1. ) / ( (double)myTexFontWidth - 1. );
282 aDX = ( (double)myWidths[aLettIndex] - 1. ) / aXScale;
284 glTexCoord2d( aLettBegin, 0.0 ); glVertex3d( theX, theY, 1.0 );
285 glTexCoord2d( aLettBegin, 1.0 ); glVertex3d( theX, theY + aDY, 1.0 );
286 glTexCoord2d( aLettEnd, 1.0 ); glVertex3d( theX + aDX, theY + aDY, 1.0 );
287 glTexCoord2d( aLettEnd, 0.0 ); glVertex3d( theX + aDX, theY, 1.0 );
289 theX += aDX + mySeparator / aXScale;
293 // restore attributes
297 //======================================================================
298 // Function: getStringWidth
300 //=======================================================================
301 int GLViewer_TexFont::getStringWidth( QString theStr )
304 for( int i = 0; i < theStr.length(); i ++ )
306 char aLetter = theStr.data()[i];
307 int aLettIndex = (int)aLetter - FirstSymbolNumber;
308 aWidth += myWidths[aLettIndex] + mySeparator;
314 //======================================================================
315 // Function: getStringHeight
317 //=======================================================================
318 int GLViewer_TexFont::getStringHeight()
320 QFontMetrics aFM( myQFont );
324 //! function for generation list base for bitmap fonts
325 static GLuint displayListBase( QFont* theFont )
328 //static QMap<GLViewer_TexFindId, GLuint> fontCache;
329 GLViewer_TexFindId aFindFont;
330 aFindFont.myFontString = theFont->toString();
333 HGLRC ctx = ::wglGetCurrentContext();
337 aFindFont.myViewPortId = (int)ctx;
339 if ( GLViewer_TexFont::BitmapFontCache.contains( aFindFont ) )
340 aList = GLViewer_TexFont::BitmapFontCache[aFindFont];
344 QMap<GLViewer_TexFindId, GLuint>::iterator it = GLViewer_TexFont::BitmapFontCache.begin();
345 for ( ; it != GLViewer_TexFont::BitmapFontCache.end(); ++it )
347 if ( it.key().myViewPortId == (int)ctx && it.data() > listBase )
348 listBase = it.data();
352 HDC glHdc = ::wglGetCurrentDC();
353 ::SelectObject( glHdc, theFont->handle() );
354 if ( !::wglUseFontBitmaps( glHdc, 0, 256, listBase ) )
357 GLViewer_TexFont::BitmapFontCache[aFindFont] = aList;
360 Display* aDisp = glXGetCurrentDisplay();
364 printf( "Can't find current dislay\n" );
369 GLXContext aCont = glXGetCurrentContext();
373 printf( "Can't find current context\n" );
378 aFindFont.myViewPortId = (int)aCont;
380 if ( GLViewer_TexFont::BitmapFontCache.contains( aFindFont ) )
381 aList = GLViewer_TexFont::BitmapFontCache[aFindFont];
385 QMap<GLViewer_TexFindId, GLuint>::iterator it = GLViewer_TexFont::BitmapFontCache.begin();
386 for ( ; it != GLViewer_TexFont::BitmapFontCache.end(); ++it )
388 if ( it.key().myViewPortId == (int)aCont && it.data() > listBase )
389 listBase = it.data();
393 //glXUseXFont( (Font)(theFont->handle()), 0, 256, listBase );
395 char** xFontList = XListFonts( aDisp, aFindFont.myFontString.data(), 1, &aFontCont );
396 if( !theFont->handle() )
399 printf( "Can't load font %s. loading default font....\n", aFindFont.myFontString.data() );
401 QString aFontMask ("-*-*-*-r-*-*-");
402 aFontMask += aFindFont.myFontString.section( ',', 1, 1 );
404 printf( "Height of Default font: %s\n", aFindFont.myFontString.section( ',', 1, 1 ).data() );
406 aFontMask += "-*-*-*-m-*-*-*";
407 xFontList = XListFonts( aDisp, aFontMask.data()/*"-*-*-*-r-*-*-12-*-*-*-m-*-*-*"*/, 1, &aFontCont );
411 printf( "Can't load default font\n" );
415 glXUseXFont( (Font)(XLoadFont( aDisp,xFontList[0] )), 0, 256, listBase );
418 glXUseXFont( (Font)(theFont->handle()), 0, 256, listBase );
421 GLViewer_TexFont::BitmapFontCache[aFindFont] = aList;
429 /***************************************************************************
430 ** Class: GLViewer_Drawer
431 ** Descr: Drawer for GLViewer_Object
433 ** Created: UI team, 01.10.01
434 ****************************************************************************/
435 //======================================================================
436 // Function: GLViewer_Drawer
438 //=======================================================================
439 GLViewer_Drawer::GLViewer_Drawer()
440 : myFont( "Helvetica", 10, QFont::Bold )
442 myXScale = myYScale = 0.0;
444 myTextList = 0/*-1*/;
445 myObjectType = "GLViewer_Object";
447 myTextFormat = DTF_BITMAP;
450 //======================================================================
451 // Function: ~GLViewer_Drawer
453 //=======================================================================
454 GLViewer_Drawer::~GLViewer_Drawer()
457 glDeleteLists( myTextList, 1 );
460 //======================================================================
461 // Function: destroyAllTextures
463 //=======================================================================
464 void GLViewer_Drawer::destroyAllTextures()
466 QMap<GLViewer_TexFindId,GLViewer_TexIdStored>::Iterator anIt= GLViewer_TexFont::TexFontBase.begin();
467 QMap<GLViewer_TexFindId,GLViewer_TexIdStored>::Iterator anEndIt= GLViewer_TexFont::TexFontBase.end();
469 for( ; anIt != anEndIt; anIt++ )
470 glDeleteTextures( 1, &(anIt.data().myTexFontId) );
473 //=======================================================================
474 // Function: setAntialiasing
475 // Purpose : The function enables and disables antialiasing in Open GL (for points, lines and polygons).
476 //=======================================================================
477 void GLViewer_Drawer::setAntialiasing(const bool on)
481 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
482 glHint(GL_POLYGON_SMOOTH_HINT, GL_NICEST);
484 glEnable(GL_POINT_SMOOTH);
485 glEnable(GL_LINE_SMOOTH);
486 glEnable(GL_POLYGON_SMOOTH);
487 glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
492 glDisable(GL_POINT_SMOOTH);
493 glDisable(GL_LINE_SMOOTH);
494 glDisable(GL_POLYGON_SMOOTH);
495 glBlendFunc (GL_ONE, GL_ZERO);
496 glDisable (GL_BLEND);
500 //======================================================================
501 // Function: loadTexture
503 //=======================================================================
504 GLuint GLViewer_Drawer::loadTexture( const QString& fileName )
507 if ( fileName.isEmpty() || !buf.load( fileName ) )
511 int h = buf.height();
514 while( size < w || size < h )
518 GLubyte* pixels = new GLubyte[ size * size * 4 ];
520 for( int i = 0; i < size; i++ )
522 for( int j = 0; j < size; j++ )
527 QRgb pixel = buf.pixel( j, h - i - 1 );
528 r = (GLubyte)qRed( pixel );
529 g = (GLubyte)qGreen( pixel );
530 b = (GLubyte)qBlue( pixel );
531 a = (GLubyte)qAlpha( pixel );
541 int index = 4 * ( i * size + j );
543 pixels[ index + 1 ] = g;
544 pixels[ index + 2 ] = b;
545 pixels[ index + 3 ] = a;
550 glPixelStorei( GL_UNPACK_ALIGNMENT, 1 );
551 glGenTextures( 1, &texture );
552 glBindTexture( GL_TEXTURE_2D, texture );
553 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
554 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
555 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, size, size, 0,
556 GL_RGBA, GL_UNSIGNED_BYTE, pixels );
563 //======================================================================
564 // Function: drawTexture
566 //=======================================================================
567 void GLViewer_Drawer::drawTexture( GLuint texture, GLint size, GLfloat x, GLfloat y )
572 glEnable( GL_TEXTURE_2D );
573 glTexEnvf( GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE );
574 bool hasAlpha = glIsEnabled( GL_ALPHA_TEST );
575 glDisable( GL_ALPHA_TEST );
577 glBindTexture( GL_TEXTURE_2D, texture );
580 glTexCoord2f( 0.0, 0.0 );
581 glVertex3f( x-size/2., y-size/2., 0.0 );
583 glTexCoord2f( 0.0, 1.0 );
584 glVertex3f( x-size/2., y+size/2., 0.0 );
586 glTexCoord2f( 1.0, 1.0 );
587 glVertex3f( x+size/2., y+size/2., 0.0 );
589 glTexCoord2f( 1.0, 0.0 );
590 glVertex3f( x+size/2., y-size/2., 0.0 );
595 glEnable( GL_ALPHA_TEST );
596 glDisable( GL_TEXTURE_2D );
599 //======================================================================
600 // Function: drawText
602 //=======================================================================
603 void GLViewer_Drawer::drawText( const QString& text, GLfloat xPos, GLfloat yPos,
604 const QColor& color, QFont* theFont, int theSeparator, DisplayTextFormat theFormat )
606 glColor3f( ( GLfloat )color.red() / 255,
607 ( GLfloat )color.green() / 255,
608 ( GLfloat )color.blue() / 255 );
610 if( theFormat != DTF_BITMAP )
612 GLViewer_TexFont aTexFont( theFont, theSeparator, theFormat == DTF_TEXTURE_SCALABLE, GL_LINEAR );
613 aTexFont.generateTexture();
614 aTexFont.drawString( text, xPos, yPos );
618 glRasterPos2f( xPos, yPos );
619 glListBase( displayListBase( theFont ) );
620 glCallLists( text.length(), GL_UNSIGNED_BYTE, text.local8Bit().data() );
624 //======================================================================
625 // Function: drawText
627 //=======================================================================
628 void GLViewer_Drawer::drawText( GLViewer_Object* theObject )
633 GLViewer_Text* aText = theObject->getGLText();
637 GLfloat aPosX, aPosY;
638 aText->getPosition( aPosX, aPosY );
639 // get temporary copy of font
640 QFont aTmpVarFont = aText->getFont();
641 drawText( aText->getText(), aPosX, aPosY, aText->getColor(), &aTmpVarFont, aText->getSeparator(), aText->getDisplayTextFormat() );
644 //======================================================================
645 // Function: drawGLText
647 //=======================================================================
648 void GLViewer_Drawer::drawGLText( QString text, float x, float y,
649 int hPosition, int vPosition, QColor color, bool smallFont )
651 QFont aFont( myFont );
653 aFont.setPointSize( aFont.pointSize() * 0.8 );
655 QFontMetrics aFontMetrics( aFont );
656 float width = myTextFormat == DTF_TEXTURE_SCALABLE ? aFontMetrics.width( text ) : aFontMetrics.width( text ) / myXScale;
657 float height = myTextFormat == DTF_TEXTURE_SCALABLE ? aFontMetrics.height() : aFontMetrics.height() / myYScale;
658 float gap = 5 / myXScale;
662 case GLText_Left : x -= ( gap + width ); break;
663 case GLText_Center : x -= width / 2; break;
664 case GLText_Right : x += gap; break;
670 case GLText_Top : y += height * 0.5; break;
671 case GLText_Center : y -= height * 0.5; break;
672 case GLText_Bottom : y -= height * 1.5; break;
676 drawText( text, x, y, color, &aFont, 2, myTextFormat );
679 //======================================================================
680 // Function: drawRectangle
682 //=======================================================================
683 void GLViewer_Drawer::drawRectangle( GLViewer_Rect* rect, QColor color )
688 float x1 = rect->left();
689 float x2 = rect->right();
690 float y1 = rect->bottom();
691 float y2 = rect->top();
693 glColor3f( ( GLfloat )color.red() / 255,
694 ( GLfloat )color.green() / 255,
695 ( GLfloat )color.blue() / 255 );
698 glBegin( GL_LINE_LOOP );
699 glVertex2f( x1, y1 );
700 glVertex2f( x1, y2 );
701 glVertex2f( x2, y2 );
702 glVertex2f( x2, y1 );
706 //======================================================================
707 // Function: translateToHPGL
709 //=======================================================================
710 bool GLViewer_Drawer::translateToHPGL( QFile& hFile, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aHPGLCS )
713 for( int i=0, n=myObjects.count(); i<n; i++ )
714 result &= myObjects[i]->translateToHPGL( hFile, aViewerCS, aHPGLCS );
718 //======================================================================
719 // Function: translateToPS
721 //=======================================================================
722 bool GLViewer_Drawer::translateToPS( QFile& hFile, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aPSCS )
725 for( int i=0, n=myObjects.count(); i<n; i++ )
726 result &= myObjects[i]->translateToPS( hFile, aViewerCS, aPSCS );
731 //======================================================================
732 // Function: translateToEMF
734 //=======================================================================
735 bool GLViewer_Drawer::translateToEMF( HDC hDC, GLViewer_CoordSystem* aViewerCS, GLViewer_CoordSystem* aEMFCS )
738 for( int i=0, n=myObjects.count(); i<n; i++ )
739 result &= myObjects[i]->translateToEMF( hDC, aViewerCS, aEMFCS );