From: san Date: Thu, 19 Jan 2006 17:29:28 +0000 (+0000) Subject: Debug: implementation of multi-row textures for texture-mapped fonts, to avoid text... X-Git-Tag: CTH_V1_0_3~6 X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=9bf5dcd91cd49038422d2b7e75c20b9ca7385a7c;p=modules%2Fgui.git Debug: implementation of multi-row textures for texture-mapped fonts, to avoid text problems on old graphic cards with small maximum texture dimensions --- diff --git a/src/GLViewer/GLViewer_Drawer.cxx b/src/GLViewer/GLViewer_Drawer.cxx index a87052ef9..7e91bd6d2 100644 --- a/src/GLViewer/GLViewer_Drawer.cxx +++ b/src/GLViewer/GLViewer_Drawer.cxx @@ -37,17 +37,14 @@ #include #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 diff --git a/src/GLViewer/GLViewer_Drawer.h b/src/GLViewer/GLViewer_Drawer.h index a5589749a..4287cdfa9 100644 --- a/src/GLViewer/GLViewer_Drawer.h +++ b/src/GLViewer/GLViewer_Drawer.h @@ -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 TexFontBase; //! Map for strorage generated bitmaps fonts static QMap 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; }; /***************************************************************************