]> SALOME platform Git repositories - modules/gui.git/commitdiff
Salome HOME
Debug: implementation of multi-row textures for texture-mapped fonts, to avoid text...
authorsan <san@opencascade.com>
Thu, 19 Jan 2006 17:29:28 +0000 (17:29 +0000)
committersan <san@opencascade.com>
Thu, 19 Jan 2006 17:29:28 +0000 (17:29 +0000)
src/GLViewer/GLViewer_Drawer.cxx
src/GLViewer/GLViewer_Drawer.h

index a87052ef9926411a0ea410ebe43c41b930694ce5..7e91bd6d2411c4eb5d923b866b7b31462f59a458 100644 (file)
 #include <qpainter.h>
 
 #define TEXT_GAP    5
+// Two texture components for texmapped fonts: luminance and alpha
+#define NB_TEX_COMP 2
+// A font is split into rows each containing 32 characters
+#define TEX_ROW_LEN 32
+// Gap in pixels between two character rows in a font texture
+#define TEX_ROW_GAP 2
 
-GLboolean          TFLoaded = GL_FALSE;
-
-GLdouble           modelMatrix[16], projMatrix[16];
-GLint              viewport[4];
-GLdouble           winx, winy, winz;
-GLint              status;
-
-GLViewer_TexFont*  staticGlFont;
-
-//static float text_scale_factor = 32.;
+GLfloat modelMatrix[16];
 
 //================================================================
 // Class       : GLViewer_TexFont
@@ -77,24 +74,14 @@ void GLViewer_TexFont::clearTextBases()
 // Purpose :
 //=======================================================================
 GLViewer_TexFont::GLViewer_TexFont()
+: myMaxRowWidth( 0 ), myFontHeight( 0 )
 {
     myQFont = QFont::defaultFont();
-    QFontMetrics aFM( myQFont );        
-    myWidths = new int[LastSymbolNumber - FirstSymbolNumber+1];
-    myPositions = new int[LastSymbolNumber - FirstSymbolNumber+1];
     mySeparator = 2;
-    for( int k = FirstSymbolNumber, aWidth = 0; k <= LastSymbolNumber; k++ )
-    {
-        myWidths[ k - FirstSymbolNumber ] = aFM.width( k );
-        myPositions[ k - FirstSymbolNumber ] = aWidth;
-        aWidth += myWidths[ k - FirstSymbolNumber ] + 2;//mySeparator;
-    }
-
-    myTexFontWidth = 0;
-    myTexFontHeight = 0; 
     myIsResizeable = false;
-    //myMinMagFilter = GL_NEAREST;
-    myMinMagFilter = GL_LINEAR_ATTENUATION ;
+    myMinMagFilter = GL_LINEAR;
+
+    init();
 }
 
 //======================================================================
@@ -102,24 +89,14 @@ GLViewer_TexFont::GLViewer_TexFont()
 // Purpose :
 //=======================================================================
 GLViewer_TexFont::GLViewer_TexFont( QFont* theFont, int theSeparator, bool theIsResizeable, GLuint theMinMagFilter )
+: myMaxRowWidth( 0 ), myFontHeight( 0 )
 {
     myQFont = *theFont;
-    QFontMetrics aFM( myQFont );        
-    myWidths = new int[LastSymbolNumber - FirstSymbolNumber+1];
-    myPositions = new int[LastSymbolNumber - FirstSymbolNumber+1];
     mySeparator = theSeparator;
-    for( int k = FirstSymbolNumber, aWidth = 0; k <= LastSymbolNumber; k++ )
-    {
-        myWidths[ k - FirstSymbolNumber ] = aFM.width( k );
-        myPositions[ k - FirstSymbolNumber ] = aWidth;
-        aWidth += myWidths[ k - FirstSymbolNumber ] + 2;//mySeparator;
-    }
-
-    myTexFontWidth = 0;
-    myTexFontHeight = 0;
     myIsResizeable = theIsResizeable;
     myMinMagFilter = theMinMagFilter;
-    
+
+    init();
 }
 
 //======================================================================
@@ -131,15 +108,50 @@ GLViewer_TexFont::~GLViewer_TexFont()
     delete[] myWidths;
     delete[] myPositions;
 } 
+
+//======================================================================
+// Function: init
+// Purpose :
+//=======================================================================
+void GLViewer_TexFont::init()
+{
+    myNbSymbols = LastSymbolNumber - FirstSymbolNumber + 1;
+
+    // It is unsafe to draw all characters in a single row -
+    // this leads to problems on some graphic cards with small GL_MAX_TEXTURE_SIZE.
+    // So splitting the characters into rows each containing 32 characters (or less).
+    // Assuming contant height of each row (64 pixels) to simplify texture mapping.
+    // However, this can be improved if necessary.
+    QFontMetrics aFM( myQFont ); 
+    myFontHeight = aFM.height();
+    
+    myWidths    = new int[myNbSymbols];
+    myPositions = new int[myNbSymbols];
+
+    for( int i = 0, k = FirstSymbolNumber, aWidth = 0; i < myNbSymbols; i++, k++ )
+    {
+        // is it time to start a new row?
+        if ( !( i % TEX_ROW_LEN ) )
+        {
+          if( aWidth > myMaxRowWidth )
+            myMaxRowWidth = aWidth;
+          aWidth = 0;
+        }
+        myWidths[i]    = aFM.width( k );
+        myPositions[i] = aWidth;
+        aWidth += myWidths[i] + 2;
+    }
+
+    myTexFontWidth  = 0;
+    myTexFontHeight = 0;
+}
   
 //======================================================================
 // Function: generateTexture
 // Purpose :
 //=======================================================================
-void GLViewer_TexFont::generateTexture()
+bool GLViewer_TexFont::generateTexture()
 {
-    QFontMetrics aFM( myQFont );
-
     GLViewer_TexFindId aFindFont;
     aFindFont.myFontFamily = myQFont.family();//myQFont.toString();
     aFindFont.myIsBold = myQFont.bold();
@@ -157,34 +169,51 @@ void GLViewer_TexFont::generateTexture()
     }    
     else    
     {
-        QString aStr;
-        int pixelsWidth = 0;
-        int pixelsHight = aFM.height();
-        myTexFontWidth = 64;
+        // Adding some pixels to have a gap between rows
+        int aRowPixelHeight = myFontHeight + TEX_ROW_GAP;
+        int aDescent = QFontMetrics( myQFont ).descent();
+
+        int aNumRows = myNbSymbols / TEX_ROW_LEN;
+        if ( myNbSymbols % TEX_ROW_LEN ) 
+          aNumRows++;
+        int pixelsHight = aNumRows * aRowPixelHeight;
+
+        myTexFontWidth  = 64;
         myTexFontHeight = 64;
-    
-        pixelsWidth = myWidths[LastSymbolNumber - FirstSymbolNumber] + 
-                      myPositions[LastSymbolNumber - FirstSymbolNumber];
 
-        while( myTexFontWidth < pixelsWidth )
-            myTexFontWidth = myTexFontWidth * 2;
+        while( myTexFontWidth < myMaxRowWidth )
+            myTexFontWidth <<= 1;
         while( myTexFontHeight < pixelsHight )
-            myTexFontHeight = myTexFontHeight * 2;
+            myTexFontHeight <<= 1;
+        
+        // Checking whether the texture dimensions for the requested font
+        // do not exceed the maximum size supported by the OpenGL implementation
+        int maxSize;
+        glGetIntegerv( GL_MAX_TEXTURE_SIZE, &maxSize );
+        if ( myTexFontWidth > maxSize || myTexFontHeight > maxSize )
+          return false;
 
         QPixmap aPixmap( myTexFontWidth, myTexFontHeight );
         aPixmap.fill( QColor( 0, 0, 0) );
         QPainter aPainter( &aPixmap );
         aPainter.setFont( myQFont );
-        for( int l = 0/*, gap = 0*/; l < LastSymbolNumber - FirstSymbolNumber; l++  )
+        int row;
+        for( int l = 0; l < myNbSymbols; l++  )
         {
+            row = l / TEX_ROW_LEN;
             QString aLetter;
             aLetter += (char)(FirstSymbolNumber + l);
             aPainter.setPen( QColor( 255,255,255) );
-            aPainter.drawText ( myPositions[l], pixelsHight, aLetter );
+            aPainter.drawText( myPositions[l], ( row + 1 ) * aRowPixelHeight - aDescent, aLetter );
         }
     
         QImage aImage = aPixmap.convertToImage();
-        char* pixels = new char[myTexFontWidth * myTexFontHeight * 2];
+
+        //int qqq = 0;
+        //if (qqq)
+        //  aImage.save("w:\\work\\CATHARE\\texture.png", "PNG");
+
+        char* pixels = new char[myTexFontWidth * myTexFontHeight * NB_TEX_COMP];
 
         for( int i = 0; i < myTexFontHeight; i++ )
         {            
@@ -196,13 +225,13 @@ void GLViewer_TexFont::generateTexture()
           
                 if( aRed != 0 || aGreen != 0 || aBlue != 0 )
                 {
-                    pixels[i * myTexFontWidth * 2 + j * 2] = (GLubyte)( (aRed + aGreen + aBlue)/3 );
-                    pixels[i * myTexFontWidth * 2 + j * 2 + 1]= (GLubyte) 255;
+                    pixels[i * myTexFontWidth * NB_TEX_COMP + j * NB_TEX_COMP] = (GLubyte)( (aRed + aGreen + aBlue)/3 );
+                    pixels[i * myTexFontWidth * NB_TEX_COMP + j * NB_TEX_COMP + 1]= (GLubyte) 255;
                 }
                 else
                 {
-                    pixels[i * myTexFontWidth * 2 + j * 2] = (GLubyte) 0;
-                    pixels[i * myTexFontWidth * 2 + j * 2 + 1]= (GLubyte) 0;
+                    pixels[i * myTexFontWidth * NB_TEX_COMP + j * NB_TEX_COMP] = (GLubyte) 0;
+                    pixels[i * myTexFontWidth * NB_TEX_COMP + j * NB_TEX_COMP + 1]= (GLubyte) 0;
                 }                
             }
         }
@@ -210,11 +239,8 @@ void GLViewer_TexFont::generateTexture()
         glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
         glGenTextures(1, &myTexFont);
         glBindTexture(GL_TEXTURE_2D, myTexFont);  
-        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
-        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, myMinMagFilter);
         glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, myMinMagFilter);
-        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
         glTexImage2D(GL_TEXTURE_2D, 
                      0, 
                      GL_INTENSITY, 
@@ -234,6 +260,7 @@ void GLViewer_TexFont::generateTexture()
 
         TexFontBase.insert( aFindFont, aTexture );
     }
+    return true;
 }
 
 //======================================================================
@@ -242,25 +269,26 @@ void GLViewer_TexFont::generateTexture()
 //=======================================================================
 void GLViewer_TexFont::drawString( QString theStr, GLdouble theX , GLdouble theY, GLfloat theScale )
 {
-    double aXScale = 1., aYScale = 1.;
-    // store attributes
-    glPushAttrib( GL_ENABLE_BIT | GL_TEXTURE_BIT );
+    // Adding some pixels to have a gap between rows
+    int aRowPixelHeight = myFontHeight + TEX_ROW_GAP;
 
+    float aXScale = 1.f, aYScale = 1.f;
     if ( !myIsResizeable )
     {
-      glGetDoublev (GL_MODELVIEW_MATRIX, modelMatrix);
+      glGetFloatv (GL_MODELVIEW_MATRIX, modelMatrix);
       aXScale = modelMatrix[0];
       aYScale = modelMatrix[5];     
-    }     
-    
-    glEnable(GL_TEXTURE_2D);
+    } 
+    else if ( theScale > 0.f )
+    {
+      aXScale = aXScale / theScale;
+      aYScale = aYScale / theScale;
+    }
 
-    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
-    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
-    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
-    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, myMinMagFilter);
-    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, myMinMagFilter);
+    // store attributes
+    glPushAttrib( GL_ENABLE_BIT | GL_TEXTURE_BIT );
 
+    glEnable(GL_TEXTURE_2D);
     glPixelTransferi(GL_MAP_COLOR, 0);
 
     glAlphaFunc(GL_GEQUAL, 0.05F);
@@ -270,34 +298,31 @@ void GLViewer_TexFont::drawString( QString theStr, GLdouble theX , GLdouble theY
     glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
 
     glBindTexture(GL_TEXTURE_2D, myTexFont);
-    glBegin(GL_QUADS);
-
-    if ( myIsResizeable && theScale > 0. )
-    {
-      aXScale = aXScale / theScale;
-      aYScale = aYScale / theScale;
-    }
+    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
 
-    theY = theY - ( myTexFontHeight - QFontMetrics( myQFont ).height() ) / aYScale;
-    
+    glBegin(GL_QUADS);
 
-    double aLettBegin, aLettEnd, aDY = ( myTexFontHeight - 1 ) / aYScale, aDX;
+    float aLettBeginS, aLettEndS, aLettBeginT, aLettEndT;
+    float aDY = ( aRowPixelHeight - 1 ) / aYScale, aDX;
     char aLetter;
-    int aLettIndex;
+    int aLettIndex, row;
     for( int i = 0; i < theStr.length(); i++ )
     {
         aLetter    = theStr.data()[i];
         aLettIndex = (int)aLetter - FirstSymbolNumber;
+        row        = aLettIndex / TEX_ROW_LEN;
 
-        aLettBegin = (double)myPositions[aLettIndex] / ( (double)myTexFontWidth - 1. );
-        aLettEnd   = aLettBegin + ( (double)myWidths[aLettIndex] - 1. ) / ( (double)myTexFontWidth - 1. );
+        aLettBeginS = (float)myPositions[aLettIndex] / ( (float)myTexFontWidth - 1.f );
+        aLettEndS   = aLettBeginS + ( (float)myWidths[aLettIndex] - 1.f ) / ( (float)myTexFontWidth - 1.f );
+        aLettBeginT = ( myTexFontHeight - ( row + 1 ) * aRowPixelHeight ) / ( (float)myTexFontHeight - 1.f ); 
+        aLettEndT   = aLettBeginT + ( (float)aRowPixelHeight - 1.f ) / ( (float)myTexFontHeight - 1.f );
 
-        aDX = ( (double)myWidths[aLettIndex] - 1. ) / aXScale;
+        aDX = ( (float)myWidths[aLettIndex] - 1.f ) / aXScale;
 
-        glTexCoord2d( aLettBegin, 0.0 ); glVertex3d( theX,       theY,       1.0 );
-        glTexCoord2d( aLettBegin, 1.0 ); glVertex3d( theX,       theY + aDY, 1.0 );
-        glTexCoord2d( aLettEnd,   1.0 ); glVertex3d( theX + aDX, theY + aDY, 1.0 );
-        glTexCoord2d( aLettEnd,   0.0 ); glVertex3d( theX + aDX, theY,       1.0 );
+        glTexCoord2f( aLettBeginS, aLettBeginT ); glVertex3f( theX,       theY,       1.f );
+        glTexCoord2f( aLettBeginS, aLettEndT   ); glVertex3f( theX,       theY + aDY, 1.f );
+        glTexCoord2f( aLettEndS,   aLettEndT   ); glVertex3f( theX + aDX, theY + aDY, 1.f );
+        glTexCoord2f( aLettEndS,   aLettBeginT ); glVertex3f( theX + aDX, theY,       1.f );
 
         theX += aDX + mySeparator / aXScale;
     }
@@ -737,7 +762,10 @@ void GLViewer_Drawer::drawText( const QString& text, GLfloat xPos, GLfloat yPos,
   if( theFormat != DTF_BITMAP )
   {
     GLViewer_TexFont aTexFont( theFont, theSeparator, theFormat == DTF_TEXTURE_SCALABLE, GL_LINEAR );
-    aTexFont.generateTexture();
+    // Font texture was not found or generated --> cannot draw text
+    if ( !aTexFont.generateTexture() )
+      return;
+
     if ( theFormat == DTF_TEXTURE_SCALABLE )
       aTexFont.drawString( text, xPos, yPos, textScale() );
     else
index a5589749ac110cd8a85e5d9ad7447ad150d6aafc..4287cdfa9df24e65e7ff24d04bd71b7225d16f4e 100644 (file)
@@ -128,7 +128,7 @@ public:
   ~GLViewer_TexFont();
   
   //! Generating font texture
-  void            generateTexture();
+  bool            generateTexture();
   //! Drawing string theStr in point with coords theX and theY
   void            drawString( QString  theStr,
                               GLdouble theX = 0.0,
@@ -152,8 +152,14 @@ public:
   static QMap<GLViewer_TexFindId,GLViewer_TexIdStored> TexFontBase;
   //! Map for strorage generated bitmaps fonts
   static QMap<GLViewer_TexFindId,GLuint>               BitmapFontCache;
+
+private:
+  //! Initializes font parameters
+  void            init();
   
-protected:
+private:
+  //! Number of characters in the font texture
+  int             myNbSymbols;
   //! Array of letter width
   int*            myWidths;
   //! Array of letter positions in texture
@@ -172,6 +178,10 @@ protected:
   bool            myIsResizeable;
   //! Min/mag filter
   GLuint          myMinMagFilter;
+  //! Font height
+  int             myFontHeight;
+  //! Diagnostic information
+  int             myMaxRowWidth;
 };
 
 /***************************************************************************