0022149: Strings with Japanese characters can not be displayed in 3D viewer
[occt.git] / src / OpenGl / OpenGl_TextRender.cxx
1 /*
2 * Includes
3 */
4 #include <stdio.h>
5 #include <string.h>
6
7 #include <TCollection_AsciiString.hxx>
8 #include <TCollection_HAsciiString.hxx>
9
10 #include <Standard_Stream.hxx>
11
12 #include <OpenGl_FontMgr.hxx>   
13 #include <OpenGl_tgl_funcs.hxx>
14 #include <OpenGl_TextRender.hxx>
15 #include <OpenGl_telem_attri.hxx>
16 #include <OpenGl_cmn_varargs.hxx>
17
18 #include <OSD_Environment.hxx>
19 #include <Quantity_NameOfColor.hxx>
20 #include <AlienImage.hxx>
21
22 #ifdef HAVE_GL2PS
23 #include <gl2ps.h>
24 #endif
25
26 /*-----------------------------------------------------------------------------*/
27 /*
28 * Prototypes variables statiques
29 */                                                 
30
31 int OpenGl_TextRender::curFont    = -1;
32 int OpenGl_TextRender::curSize    = -1;
33 int OpenGl_TextRender::curScale   = -1;
34 int OpenGl_TextRender::curTexFont = -1;
35
36 OpenGl_TextRender::FontMapNode OpenGl_TextRender::fontMap[] = {
37
38 #ifdef WNT
39
40   { "Courier"                  , "Courier New"    , OSD_FA_Regular },
41   { "Times-Roman"              , "Times New Roman", OSD_FA_Regular  },
42   { "Times-Bold"               , "Times New Roman", OSD_FA_Bold },
43   { "Times-Italic"             , "Times New Roman", OSD_FA_Italic  },
44   { "Times-BoldItalic"         , "Times New Roman", OSD_FA_BoldItalic  },
45   { "ZapfChancery-MediumItalic", "Script"         , OSD_FA_Regular  },
46   { "Symbol"                   , "Symbol"         , OSD_FA_Regular  },
47   { "ZapfDingbats"             , "WingDings"      , OSD_FA_Regular  },
48   { "Rock"                     , "Arial"          , OSD_FA_Regular  },
49   { "Iris"                     , "Lucida Console" , OSD_FA_Regular  }
50
51 #else   //X11
52
53   { "Courier"                  , "Courier"      , OSD_FA_Regular },
54   { "Times-Roman"              , "Times"        , OSD_FA_Regular  },
55   { "Times-Bold"               , "Times"        , OSD_FA_Bold },
56   { "Times-Italic"             , "Times"        , OSD_FA_Italic  },
57   { "Times-BoldItalic"         , "Times"        , OSD_FA_BoldItalic  },
58   { "Arial"                    , "Helvetica"    , OSD_FA_Regular  }, 
59   { "ZapfChancery-MediumItalic", "-adobe-itc zapf chancery-medium-i-normal--*-*-*-*-*-*-iso8859-1"              , OSD_FA_Regular  },
60   { "Symbol"                   , "-adobe-symbol-medium-r-normal--*-*-*-*-*-*-adobe-fontspecific"                , OSD_FA_Regular  },
61   { "ZapfDingbats"             , "-adobe-itc zapf dingbats-medium-r-normal--*-*-*-*-*-*-adobe-fontspecific"     , OSD_FA_Regular  },
62   { "Rock"                     , "-sgi-rock-medium-r-normal--*-*-*-*-p-*-iso8859-1"                             , OSD_FA_Regular  },
63   { "Iris"                     , "--iris-medium-r-normal--*-*-*-*-m-*-iso8859-1"                                , OSD_FA_Regular  }
64 #endif
65
66 };  
67
68 OpenGl_TextRender::FontEntry OpenGl_TextRender::fontEntry[] = {
69
70   { "Courier"                  , "Courier New"                 },
71   { "Times-Roman"              , "Times New Roman"             },
72   { "Times-Bold"               , "Times New Roman Bold"        },
73   { "Times-Italic"             , "Times New Roman Italic"      },
74   { "Times-BoldItalic"         , "Times New Roman Bold Italic" },
75   { "ZapfChancery-MediumItalic", "Script"                      },
76   { "Symbol"                   , "Symbol"                      },
77   { "ZapfDingbats"             , "WingDings"                   },
78   { "Rock"                     , "Arial"                       },
79   { "Iris"                     , "Lucida Console"              }
80
81 };
82
83 #define NUM_FONT_ENTRIES (sizeof(fontMap)/sizeof(FontMapNode))
84
85 /*-----------------------------------------------------------------------------*/
86
87 /*
88 *  Constants
89 */
90
91 #ifdef HAVE_GL2PS
92 void OpenGl_TextRender::getGL2PSFontName(char *src_font, char *ps_font)
93 {
94   /* 
95   Convert font name used for rendering to some "good" font names
96   that produce good vector text 
97   */
98   static char const *family[] = {"Helvetica", "Courier", "Times"};
99   static char const *italic[] = {"Oblique", "Oblique", "Italic"};
100   static char const *base[] = {"", "", "-Roman"};
101
102   int font = 0;
103   int isBold = 0;
104   int isItalic = 0;
105
106
107   if( strstr( src_font, "Symbol" ) ){
108     sprintf( ps_font, "%s", "Symbol" );
109     return;
110   }
111
112   if( strstr( src_font, "ZapfDingbats" ) ){
113     sprintf( ps_font, "%s", "WingDings" );
114     return;
115   }
116
117   if ( strstr( src_font, "Courier" ) ){
118     font = 1;
119   }
120   else if ( strstr( src_font, "Times" ) ){
121     font = 2;
122   }
123
124   if ( strstr( src_font, "Bold" ) ){
125     isBold = 1;
126   }
127
128   if ( strstr( src_font, "Italic" ) || strstr( src_font, "Oblique" ) ){
129     isItalic = 1;
130   }
131
132   if ( isBold ){
133     sprintf( ps_font, "%s-%s", family[font], "Bold");
134     if ( isItalic ){
135       sprintf(ps_font, "%s%s", ps_font, italic[font]);
136     }
137   }
138   else if ( isItalic )
139   {
140     sprintf( ps_font, "%s-%s", family[font], italic[font] );
141   }
142   else
143   {
144     sprintf( ps_font, "%s%s", family[font], base[font] );
145   }
146 }
147 #endif
148
149 /*-----------------------------------------------------------------------------*/
150
151 /*
152 * Constructors
153 */
154
155 OpenGl_TextRender::OpenGl_TextRender()
156 : _CurrentFontId(-1),
157 _XCurrentScale(1.f),
158 _YCurrentScale(1.f) {
159 }
160
161
162
163 /*-----------------------------------------------------------------------------*/
164
165 /*
166 * Fonctions publiques 
167 */
168
169 OpenGl_TextRender* OpenGl_TextRender::instance() {
170   static OpenGl_TextRender* _textRend = NULL;
171   if ( _textRend == NULL )
172   {
173     _textRend = new OpenGl_TextRender();
174   }
175
176   return _textRend;
177 }
178
179
180 /*----------------------------------------------------------------------*/
181 OpenGl_TextRender::FontMapNode OpenGl_TextRender::searchFontInMap( Handle(TCollection_HAsciiString)& fontName ) {
182   for ( int i = 0; i < NUM_FONT_ENTRIES; ++i )
183   {
184     TCollection_AsciiString compare_String(fontMap[i].enumName) ;
185     if(compare_String.IsEqual( fontName->ToCString() ))
186     {
187       return fontMap[i];
188     }  
189   }   
190   //default font returns
191   return fontMap[0];
192 }
193
194 /*-----------------------------------------------------------------------------*/
195
196 Tint OpenGl_TextRender::FindFont ( Tchar* fontName,
197                                   OSD_FontAspect aspect,
198                                   Tfloat bestSize,
199                                   Tfloat xScale ,
200                                   Tfloat yScale ) 
201 {   
202   if (!fontName)
203     return -1;
204   OpenGl_FontMgr* mgr =  OpenGl_FontMgr::instance();  
205
206   Handle(TCollection_HAsciiString) family_name
207     = new TCollection_HAsciiString((char*)fontName);
208
209   curFont = mgr->request_font(family_name,
210     aspect,
211     Standard_Integer(bestSize) );
212
213   if( curFont == -1 ) {
214     //try to use font names mapping
215     FontMapNode newTempFont = searchFontInMap ( family_name );
216     curFont = mgr->request_font( new TCollection_HAsciiString(newTempFont.FontName),
217       newTempFont.fontAspect,
218       Standard_Integer(bestSize) );
219   }
220
221   // Requested family name not found -> serach for any font family with given aspect and height
222   family_name = new TCollection_HAsciiString( "" );
223   if ( curFont == -1 ) {
224     curFont = mgr->request_font(family_name, aspect, Standard_Integer(bestSize) );
225   }
226
227   // The last resort: trying to use ANY font available in the system
228   if ( curFont == -1 ) {
229     curFont = mgr->request_font(family_name, OSD_FA_Undefined, -1 );
230   }
231
232   if ( curFont != -1 )
233     mgr->setCurrentScale( xScale, yScale );
234   return curFont;
235
236 }
237
238 /*-----------------------------------------------------------------------------*/
239 void OpenGl_TextRender::StringSize(const wchar_t *str, GLint *Width, GLint *Ascent, GLint *Descent)
240 {
241
242   /*    int       dir, asc, des;*/
243   *Ascent = 0;
244   *Descent = 0;
245   *Width = 0;
246   if (curFont != -1) {
247     OpenGl_FontMgr* mgr = OpenGl_FontMgr::instance();
248     const FTFont* font = mgr->fontById( curFont );
249     if ( font ) {
250       *Width = GLint( mgr->computeWidth( curFont, str ) );
251       *Ascent = GLint( font->Ascender() );
252       *Descent = GLint( font->Descender() );
253     }
254   }
255 #ifdef TRACE
256   printf("sizeString::asc = %d des = %d width = %d \n", *Ascent, *Descent, *Width); 
257 #endif
258
259 }
260
261 /*-----------------------------------------------------------------------------*/
262
263 void OpenGl_TextRender::RenderText ( const wchar_t* str, GLuint base, int is2d, GLfloat x, GLfloat y, GLfloat z ) 
264 {
265   GLdouble projMatrix[4][4], modelMatrix[4][4];
266   GLint viewport[4];
267   GLint widthFont, ascentFont, descentFont;
268   GLdouble xdis = 0., ydis = 0.;
269   GLint renderMode;  
270
271   // FTFont changes texture state when it renders and computes size for the text
272   glPushAttrib(GL_TEXTURE_BIT);
273   StringSize(str, &widthFont, &ascentFont, &descentFont );
274
275   GLdouble identityMatrix[4][4] = 
276   {
277     {1.,0.,0.,0.},
278     {0.,1.,0.,0.},
279     {0.,0.,1.,0.},
280     {0.,0.,0.,1.}
281   };
282
283   TEL_ALIGN_DATA align;
284
285   CMN_KEY key;
286   key.id = TelTextAlign;
287   key.data.pdata = &align;
288   TsmGetAttri( 1, &key );
289
290   Tfloat angle = 0;
291   CMN_KEY keyAngle;
292   keyAngle.id = TelTextAngle;//This flag responding about Angle text
293   TsmGetAttri( 1, &keyAngle );
294   angle = keyAngle.data.ldata;
295
296   Tint zoom = 0;
297   CMN_KEY keyZoom;
298   keyZoom.id = TelTextZoomable;//This flag responding about Zoomable text
299   TsmGetAttri( 1, &keyZoom );
300   zoom = keyZoom.data.ldata;
301
302   OpenGl_TextRender* textRender = OpenGl_TextRender::instance(); 
303   int vh = 2 ;
304   int vv = 2 ;
305
306   switch( align.Hmode )
307   {
308   case CALL_PHIGS_HOR_LEFT://0
309     xdis =0.; vh = 1;
310     break;
311   case CALL_PHIGS_HOR_CENTER://1
312     xdis = -(GLdouble)widthFont / 2.0;  vh = 2;
313     break;
314   case CALL_PHIGS_HOR_RIGHT://2
315     xdis = -(GLdouble)widthFont; vh = 3;
316     break;
317   default:
318     xdis = 0.;
319   }
320
321   switch( align.Vmode )
322   {
323   case CALL_PHIGS_VERT_BOTTOM://0
324     ydis = 0.; vv = 1;
325     break;
326   case CALL_PHIGS_VERT_CENTER://1
327     ydis = -(GLdouble)(ascentFont) / 2.0 - descentFont; vv = 2;
328     break;
329   case CALL_PHIGS_VERT_TOP://2
330     ydis = -(GLdouble)ascentFont - descentFont; vv= 3;
331     break;    
332   default:
333     ydis = 0.;
334   }
335
336   OpenGl_FontMgr* mgr = OpenGl_FontMgr::instance();
337
338   const FTFont* fnt = mgr->fontById( curFont );
339   if ( !fnt ) {
340     glPopAttrib();
341     return; 
342   }
343
344   float export_h = 1.;
345
346   glMatrixMode(GL_MODELVIEW);
347   glPushMatrix();
348   if (is2d) {
349     glLoadIdentity();
350     glTranslatef(x, y, 0.f);
351     glRotatef( 180, 1, 0, 0 );
352   }
353   else {
354     GLdouble wx, wy, wz;
355     GLdouble x1, y1, z1;
356     GLdouble x2, y2, z2;
357
358     glGetDoublev( GL_MODELVIEW_MATRIX, (GLdouble*)modelMatrix );
359     glGetDoublev( GL_PROJECTION_MATRIX, (GLdouble*)projMatrix );
360     glGetIntegerv( GL_VIEWPORT, (GLint*)viewport );
361
362     gluProject( x, y, z,
363       (GLdouble*)modelMatrix,
364       (GLdouble*)projMatrix,
365       (GLint*)viewport,
366       &wx, &wy, &wz );
367     glLoadIdentity();
368     gluUnProject( wx, wy, wz, 
369       (GLdouble*)identityMatrix, (GLdouble*)projMatrix, (GLint*)viewport,
370       &x1, &y1 , &z1 );    
371
372     GLdouble h = (GLdouble)fnt->FaceSize();
373
374
375     gluUnProject( wx, wy + h - 1., wz,
376       (GLdouble*)identityMatrix, (GLdouble*)projMatrix, (GLint*)viewport,
377       &x2, &y2, &z2 );
378
379     h = (y2-y1)/h;
380
381     glTranslated( x1, y1 , z1 );   
382     glRotated(angle, 0, 0, 1); 
383     glTranslated(xdis, ydis, 0);  
384
385     if( ! zoom )
386     {
387       glScaled( h, h, h );
388     }
389     else
390     {
391       export_h = h;
392     }
393   }
394   glGetIntegerv(GL_RENDER_MODE, &renderMode);
395   if ( renderMode == GL_FEEDBACK ) 
396   {
397 #ifdef HAVE_GL2PS
398     CMN_KEY keyfontName;
399     keyfontName.id = TelTextFont;//This flag responding about TextFontName
400     TsmGetAttri( 1, &keyfontName );
401     char *fontName = new char[strlen((char*)keyfontName.data.pdata) + 1];
402     strcpy(fontName,(char*)keyfontName.data.pdata);
403
404     export_h = (GLdouble)fnt->FaceSize() / export_h;
405     int aligment = alignmentforgl2ps( vh, vv );
406     glPopMatrix();
407     ExportText( str, fontName, export_h, angle, aligment, x, y, z, is2d!=0 );
408     delete [] fontName;
409 #endif
410   }
411   else
412   {
413     mgr->render_text( curFont, str, is2d );
414     glPopMatrix();
415   }
416   glPopAttrib();
417
418 }
419
420 #ifdef HAVE_GL2PS
421 int OpenGl_TextRender::alignmentforgl2ps(int vh, int vy)
422 {
423   if( vh == 1 && vy == 1)
424   {
425     return 5;
426   }
427   if( vh == 2 && vy == 1)
428   {
429     return 4;
430   }
431   if( vh == 3 && vy == 1)
432   {
433     return 6;
434   }
435
436   if( vh == 1 && vy == 2)
437   {
438     return 2;
439   }
440   if( vh == 2 && vy == 2)
441   {
442     return 1;
443   }
444   if( vh == 3 && vy == 2)
445   {
446     return 3;
447   }
448
449   if( vh == 1 && vy == 3)
450   {
451     return 8;
452   }
453   if( vh == 2 && vy == 3)
454   {
455     return 7;
456   }
457   if( vh == 3 && vy == 3)
458   {
459     return 9;
460   }
461   return 0;
462 };
463 #endif
464
465 /*-----------------------------------------------------------------------------*/
466 void OpenGl_TextRender::ExportText( const wchar_t* text, char* fontname, GLfloat height, GLfloat angle, GLint alignment,
467                                     GLfloat x, GLfloat y, GLfloat z, GLboolean is2d )
468 {
469 #ifdef HAVE_GL2PS
470
471   GLubyte zero = 0;
472   char ps_font[64];
473
474   getGL2PSFontName(fontname, ps_font);
475
476   if( is2d )
477     glRasterPos2f( x, y );
478   else
479     glRasterPos3f( x, y, z );
480
481   glBitmap( 1, 1, 0, 0, 0, 0, &zero );
482
483   //szv: workaround for gl2ps!
484   const int len = 4 * (wcslen(text) + 1); //szv: should be more than enough
485   char *astr = new char[len];
486   wcstombs(astr,text,len);
487   gl2psTextOpt(astr, ps_font, height, alignment, angle);
488   delete[] astr;
489
490 #endif
491 }