1 // File: OpenGl_Display_1.cxx
2 // Created: 25 October 2011
3 // Author: Sergey ZERCHANINOV
4 // Copyright: OPEN CASCADE 2011
6 #include <OpenGl_Display.hxx>
8 #include <TCollection_AsciiString.hxx>
9 #include <TCollection_HAsciiString.hxx>
11 #include <OpenGl_FontMgr.hxx>
13 #include <OpenGl_AspectText.hxx>
19 /*-----------------------------------------------------------------------------*/
21 * Prototypes variables statiques
26 const char * EnumName;
27 const char * FontName;
28 OSD_FontAspect FontAspect;
31 static const FontMapNode myFontMap[] =
36 { "Courier" , "Courier New" , OSD_FA_Regular },
37 { "Times-Roman" , "Times New Roman", OSD_FA_Regular },
38 { "Times-Bold" , "Times New Roman", OSD_FA_Bold },
39 { "Times-Italic" , "Times New Roman", OSD_FA_Italic },
40 { "Times-BoldItalic" , "Times New Roman", OSD_FA_BoldItalic },
41 { "ZapfChancery-MediumItalic", "Script" , OSD_FA_Regular },
42 { "Symbol" , "Symbol" , OSD_FA_Regular },
43 { "ZapfDingbats" , "WingDings" , OSD_FA_Regular },
44 { "Rock" , "Arial" , OSD_FA_Regular },
45 { "Iris" , "Lucida Console" , OSD_FA_Regular }
49 { "Courier" , "Courier" , OSD_FA_Regular },
50 { "Times-Roman" , "Times" , OSD_FA_Regular },
51 { "Times-Bold" , "Times" , OSD_FA_Bold },
52 { "Times-Italic" , "Times" , OSD_FA_Italic },
53 { "Times-BoldItalic" , "Times" , OSD_FA_BoldItalic },
54 { "Arial" , "Helvetica" , OSD_FA_Regular },
55 { "ZapfChancery-MediumItalic", "-adobe-itc zapf chancery-medium-i-normal--*-*-*-*-*-*-iso8859-1" , OSD_FA_Regular },
56 { "Symbol" , "-adobe-symbol-medium-r-normal--*-*-*-*-*-*-adobe-fontspecific" , OSD_FA_Regular },
57 { "ZapfDingbats" , "-adobe-itc zapf dingbats-medium-r-normal--*-*-*-*-*-*-adobe-fontspecific" , OSD_FA_Regular },
58 { "Rock" , "-sgi-rock-medium-r-normal--*-*-*-*-p-*-iso8859-1" , OSD_FA_Regular },
59 { "Iris" , "--iris-medium-r-normal--*-*-*-*-m-*-iso8859-1" , OSD_FA_Regular }
64 #define NUM_FONT_ENTRIES (sizeof(myFontMap)/sizeof(FontMapNode))
66 /*-----------------------------------------------------------------------------*/
73 void OpenGl_Display::getGL2PSFontName (const char *src_font, char *ps_font)
76 Convert font name used for rendering to some "good" font names
77 that produce good vector text
79 static char const *family[] = {"Helvetica", "Courier", "Times"};
80 static char const *italic[] = {"Oblique", "Oblique", "Italic"};
81 static char const *base[] = {"", "", "-Roman"};
87 if( strstr( src_font, "Symbol" ) ){
88 sprintf( ps_font, "%s", "Symbol" );
92 if( strstr( src_font, "ZapfDingbats" ) ){
93 sprintf( ps_font, "%s", "WingDings" );
97 if ( strstr( src_font, "Courier" ) ){
100 else if ( strstr( src_font, "Times" ) ){
104 if ( strstr( src_font, "Bold" ) ){
108 if ( strstr( src_font, "Italic" ) || strstr( src_font, "Oblique" ) ){
113 sprintf( ps_font, "%s-%s", family[font], "Bold");
115 sprintf(ps_font, "%s%s", ps_font, italic[font]);
120 sprintf( ps_font, "%s-%s", family[font], italic[font] );
124 sprintf( ps_font, "%s%s", family[font], base[font] );
129 /*-----------------------------------------------------------------------------*/
132 * Fonctions publiques
135 /*-----------------------------------------------------------------------------*/
137 int OpenGl_Display::FindFont (const char* AFontName, const OSD_FontAspect AFontAspect,
138 const int ABestSize, const float AXScale, const float AYScale)
144 myFontSize = ABestSize;
146 OpenGl_FontMgr* mgr = OpenGl_FontMgr::instance();
148 Handle(TCollection_HAsciiString) family_name = new TCollection_HAsciiString(AFontName);
149 myFont = mgr->request_font( family_name, AFontAspect, myFontSize );
153 //try to use font names mapping
154 FontMapNode newTempFont = myFontMap[0];
155 for ( int i = 0; i < NUM_FONT_ENTRIES; ++i )
157 if ( TCollection_AsciiString(myFontMap[i].EnumName).IsEqual( family_name->ToCString() ) )
159 newTempFont = myFontMap[i];
163 family_name = new TCollection_HAsciiString(newTempFont.FontName);
164 myFont = mgr->request_font( family_name, newTempFont.FontAspect, myFontSize );
167 // Requested family name not found -> serach for any font family with given aspect and height
170 family_name = new TCollection_HAsciiString( "" );
171 myFont = mgr->request_font( family_name, AFontAspect, myFontSize );
174 // The last resort: trying to use ANY font available in the system
177 myFont = mgr->request_font( family_name, OSD_FA_Undefined, -1 );
181 mgr->setCurrentScale( AXScale, AYScale );
186 /*-----------------------------------------------------------------------------*/
188 void OpenGl_Display::StringSize (const wchar_t *str, int &width, int &ascent, int &descent)
194 OpenGl_FontMgr* mgr = OpenGl_FontMgr::instance();
195 const FTFont* font = mgr->fontById( myFont );
197 width = int( mgr->computeWidth( myFont, str ) );
198 ascent = int( font->Ascender() );
199 descent = int( font->Descender() );
205 Class : MultilineTextRenderer
206 Description : Class for constructing text and multi-line text
209 class MultilineTextRenderer
213 Standard_Integer myLFNum; // Number of '\n' (Line Feed) '\x00\x0A'
214 Standard_Integer myCurrPos; // Position of the current substring
215 Standard_Integer myNewStrLen; // Length of the new string
216 Standard_Integer mySubstrNum; // Number of substrings
217 wchar_t *myNewStr; // New string
218 const wchar_t *myStrPtr; // Pointer to the original string
222 // ----------------------------------------------
223 // Function: MultilineTextRenderer
224 // Purpose: Constructor with initialization
225 // ----------------------------------------------
226 MultilineTextRenderer ( const wchar_t *theStr,
229 const OpenGl_TextParam *theParam,
230 const FTFont *theFnt,
233 GLint theDescentFont ) :
240 myStrPtr (&theStr[0])
242 const Standard_Integer aStrLen = wcslen(theStr); // Length of the original string
243 Standard_Integer aNextCRChar = 0; // Character after '\r' (Carriage Return) '\x00\x0D'
244 Standard_Integer aHTNum = 0; // Number of '\t' (Horizontal Tabulation) '\x00\x09'
245 Standard_Integer aDumpNum = 0; // Number of '\a', '\b', '\v' and '\f'
246 Standard_Integer anAllSpaces = 0; // Number of spaces instead of all '\t' characters
247 Standard_Integer aMaxSubstrLen = 0; // Length of the largest substring in the new string
249 Standard_Integer aTimeVar = 0;
251 // Calculation index after last '\r' character
252 for ( Standard_Integer anIndex = 0; anIndex < aStrLen; ++anIndex )
254 if ( theStr[anIndex] == '\r' ) aNextCRChar = anIndex+1;
257 // Calculation numbers of the some control characters
258 for (Standard_Integer anIndex = aNextCRChar; anIndex < aStrLen; anIndex++)
261 switch ( theStr[anIndex] )
276 anAllSpaces += ( 8 - ( aTimeVar - 1 )%8 );
282 // Calculation length of the new string
283 myStrPtr += aNextCRChar;
284 myNewStrLen = aStrLen - aNextCRChar + anAllSpaces - aHTNum - aDumpNum;
286 myNewStr = new wchar_t[myNewStrLen + 1];
287 myNewStr[myNewStrLen]='\0';
289 CalcString (aStrLen, aMaxSubstrLen);
290 CalcHAlign (theXdis, theParam, theWidthFont, aStrLen, aMaxSubstrLen);
291 CalcVAlign (theYdis, theParam, theFnt, theAscentFont, theDescentFont);
294 // ----------------------------------------------
295 // Function: ~MultilineTextRenderer
296 // Purpose: Default destructor
297 // ----------------------------------------------
298 ~MultilineTextRenderer ()
303 // ----------------------------------------------
305 // Purpose: Calculate position of the next substring
306 // ----------------------------------------------
309 for ( Standard_Integer anIndex = 0; anIndex <= myNewStrLen; ++anIndex )
311 if ( myNewStr[myCurrPos + anIndex] == '\0' )
314 myCurrPos += anIndex + 1;
320 // ----------------------------------------------
322 // Purpose: Calculate position of the next substring
323 // ----------------------------------------------
324 Standard_Boolean More ()
326 if ( mySubstrNum <= myLFNum ) return Standard_True;
327 else return Standard_False;
330 // ----------------------------------------------
331 // Function: GetValue
332 // Purpose: Returns current substring
333 // ----------------------------------------------
336 return ( myNewStr + myCurrPos );
341 // ----------------------------------------------
342 // Function: CalcString
343 // Purpose: Calculate new string separated by '\0' without '\n', '\t', '\b', '\v', '\f', '\a'
344 // ----------------------------------------------
345 void CalcString ( const Standard_Integer theStrLen, Standard_Integer &theMaxSubstrLen )
352 for ( Standard_Integer anIndex1 = 0, anIndex2 = 0;
353 (anIndex1 < theStrLen)&&(anIndex2 < myNewStrLen);
354 ++anIndex1, ++anIndex2 )
358 if ( *(myStrPtr + anIndex1) == '\n' ) aTimeVar = 0;
360 while ( (*(myStrPtr + anIndex1)=='\b')||(*(myStrPtr + anIndex1)=='\f')
361 ||(*(myStrPtr + anIndex1)=='\v')||(*(myStrPtr + anIndex1)=='\a') )
366 if ( *(myStrPtr + anIndex1) == '\t' )
368 aSpacesNum = ( 8 - ( aTimeVar - 1 )%8 );
370 for ( aHelpIndex = 0; aHelpIndex < aSpacesNum; aHelpIndex++ )
372 myNewStr[anIndex2 + aHelpIndex] = ' ';
374 anIndex2 += aHelpIndex - 1;
379 myNewStr[anIndex2] = *(myStrPtr + anIndex1);
383 // After this part of code we will have a string separated by '\0' characters
384 Standard_Integer aHelpLength = 0;
388 for( Standard_Integer anIndex = 0; anIndex <= myNewStrLen; ++anIndex )
390 if ( myNewStr[anIndex] == '\n' )
392 myNewStr[anIndex] = '\0';
395 // Calculating length of the largest substring of the new string.
396 // It's needed for horizontal alignment
397 if ( myNewStr[anIndex] != '\0' )
403 if ( aHelpLength > theMaxSubstrLen ) theMaxSubstrLen = aHelpLength;
411 // ----------------------------------------------
412 // Function: CalcVAlign
413 // Purpose: Calculate vertical alignment for text
414 // ----------------------------------------------
415 void CalcVAlign ( GLdouble &theYdis,
416 const OpenGl_TextParam *theParam,
417 const FTFont *theFnt,
419 GLint theDescentFont )
421 switch (theParam->VAlign)
423 case Graphic3d_VTA_BOTTOM:
424 theYdis = (GLdouble)(myLFNum * theFnt->FaceSize());
426 case Graphic3d_VTA_CENTER:
427 if ( (myLFNum%2) == 0 ) // An odd number of strings
429 theYdis = (GLdouble)((myLFNum/2.0) * theFnt->FaceSize()) + theDescentFont;
431 else // An even number of strings
433 theYdis = (GLdouble)((myLFNum - 1)/2.0 * theFnt->FaceSize()) - theDescentFont/2.0;
436 case Graphic3d_VTA_TOP:
437 theYdis = -(GLdouble)theAscentFont - theDescentFont;
440 theYdis = (GLdouble)(myLFNum * theFnt->FaceSize());
445 // ----------------------------------------------
446 // Function: CalcHAlign
447 // Purpose: Calculate horizontal alignment for text
448 // ----------------------------------------------
449 void CalcHAlign ( GLdouble &theXdis,
450 const OpenGl_TextParam *theParam,
452 const Standard_Integer theStrLen,
453 Standard_Integer theMaxSubstrLen)
455 GLdouble aWidth = (GLdouble)(theMaxSubstrLen * theWidthFont)/theStrLen;
457 switch (theParam->HAlign)
459 case Graphic3d_HTA_LEFT:
462 case Graphic3d_HTA_CENTER:
463 theXdis = -0.5 * (GLdouble)aWidth;
465 case Graphic3d_HTA_RIGHT:
466 theXdis = -(GLdouble)aWidth;
475 /*-----------------------------------------------------------------------------*/
477 void OpenGl_Display::RenderText (const wchar_t* str, const int is2d, const float x, const float y, const float z,
478 const OpenGl_AspectText *aspect, const OpenGl_TextParam *param)
480 OpenGl_FontMgr* mgr = OpenGl_FontMgr::instance();
481 const FTFont* fnt = mgr->fontById( myFont );
485 // FTFont changes texture state when it renders and computes size for the text
486 glPushAttrib(GL_TEXTURE_BIT);
488 int widthFont, ascentFont, descentFont;
489 StringSize( str, widthFont, ascentFont, descentFont );
491 GLdouble xdis = 0., ydis = 0.;
495 MultilineTextRenderer aRenderer( str,
504 glMatrixMode(GL_MODELVIEW);
509 glTranslatef(x, y, 0.f);
510 glRotatef( 180, 1, 0, 0 );
514 const GLdouble identityMatrix[4][4] =
522 GLdouble projMatrix[4][4], modelMatrix[4][4];
529 glGetDoublev( GL_MODELVIEW_MATRIX, (GLdouble*)modelMatrix );
530 glGetDoublev( GL_PROJECTION_MATRIX, (GLdouble*)projMatrix );
531 glGetIntegerv( GL_VIEWPORT, (GLint*)viewport );
534 (GLdouble*)modelMatrix,
535 (GLdouble*)projMatrix,
539 gluUnProject( wx, wy, wz,
540 (GLdouble*)identityMatrix, (GLdouble*)projMatrix, (GLint*)viewport,
543 GLdouble h = (GLdouble)fnt->FaceSize();
545 gluUnProject( wx, wy + h - 1., wz,
546 (GLdouble*)identityMatrix, (GLdouble*)projMatrix, (GLint*)viewport,
551 glTranslated( x1, y1 , z1 );
552 glRotated(aspect->Angle(), 0, 0, 1);
553 glTranslated(xdis, ydis, 0);
555 if( !aspect->IsZoomable() )
566 glGetIntegerv(GL_RENDER_MODE, &renderMode);
567 if ( renderMode == GL_FEEDBACK )
570 export_h = (float)fnt->FaceSize() / export_h;
571 for ( ; aRenderer.More(); aRenderer.Next() )
573 // x, y, z coordinates are used here as zero values, because position of the text
574 // and alignment is calculated in the code above using glTranslated methods
575 ExportText( aRenderer.GetValue(), is2d, 0, 0, 0, aspect, param, (short)export_h );
576 glTranslated(0, -(GLdouble)fnt->FaceSize(), 0);
582 for ( ; aRenderer.More(); aRenderer.Next() )
584 mgr->render_text( myFont, aRenderer.GetValue(), is2d );
585 glTranslated(0, -(GLdouble)fnt->FaceSize(), 0);
592 /*-----------------------------------------------------------------------------*/
594 void OpenGl_Display::ExportText (const wchar_t* text, const int is2d, const float x, const float y, const float z,
595 const OpenGl_AspectText *aspect, const OpenGl_TextParam *param, const short height)
599 const char* fontname = aspect->Font();
600 float angle = aspect->Angle();
605 getGL2PSFontName(fontname, ps_font);
608 glRasterPos2f( x, y );
610 glRasterPos3f( x, y, z );
612 glBitmap( 1, 1, 0, 0, 0, 0, &zero );
614 //szv: workaround for gl2ps!
615 const int len = 4 * (wcslen(text) + 1); //szv: should be more than enough
616 char *astr = new char[len];
617 wcstombs(astr,text,len);
619 // Standard GL2PS's alignment isn't used, because it doesn't work correctly
620 // for all formats, therefore alignment is calculated manually relative
621 // to the bottom-left corner, which corresponds to the GL2PS_TEXT_BL value
622 gl2psTextOpt(astr, ps_font, height, GL2PS_TEXT_BL, angle);