OCC22354 Bug in Overlay Text rendering
[occt.git] / src / OpenGl / OpenGl_FontMgr.cxx
CommitLineData
7fd59977 1#include <OpenGl_FontMgr.hxx>
2
3#include <FTGLTextureFont.h>
4#include <FTLibrary.h>
5#include <FTFace.h>
6#include <Standard_Stream.hxx>
7
8#undef TRACE
9
10#define DEFAULT_FONT_HEIGHT 16
11
12float h_scale = 0;
13
14void dump_texture( int id);
15
16class Font_DataMap:
17 public NCollection_DataMap< Handle(TCollection_HAsciiString),
18 Handle(TCollection_HAsciiString)>
19{
20public:
21 inline Font_DataMap
22 (const Standard_Integer NbBuckets = 1,
23 const Handle(NCollection_BaseAllocator)& theAllocator = 0L)
24 : NCollection_DataMap<Handle(TCollection_HAsciiString),
25 Handle(TCollection_HAsciiString)> (NbBuckets, theAllocator)
26 {}
27
28 inline Font_DataMap (const Font_DataMap& theOther)
29 : NCollection_DataMap<Handle(TCollection_HAsciiString),
30 Handle(TCollection_HAsciiString)> (theOther)
31 {}
32 friend Standard_Boolean IsEqual( const Handle(TCollection_HAsciiString)& h1,
33 const Handle(TCollection_HAsciiString)& h2 );
34};
35inline Standard_Boolean
36IsEqual( const Handle(TCollection_HAsciiString)& h1,
37 const Handle(TCollection_HAsciiString)& h2 )
38{
39 return (!h1->IsLess(h2) && !h1->IsGreater(h2));
40}
41
42OpenGl_FontMgr::OpenGl_FontMgr()
43: _CurrentFontId(-1),
44_XCurrentScale(1.f),
45_YCurrentScale(1.f)
46{
47}
48
49OpenGl_FontMgr* OpenGl_FontMgr::instance()
50{
51 static OpenGl_FontMgr* _mgr = NULL;
52 if ( _mgr == NULL )
53 {
54 _mgr = new OpenGl_FontMgr();
55 _mgr->_initializeFontDB();
56 }
57 return _mgr;
58}
59
60void OpenGl_FontMgr::_initializeFontDB()
61{
62 Handle(OSD_FontMgr) fntMgr = OSD_FontMgr::GetInstance();
63 if ( !fntMgr.IsNull() ) {
64
65 OSD_NListOfSystemFont fontList = fntMgr->GetAvalableFonts();
66 if ( fontList.Size() != 0 ) {
67
68 OSD_NListOfSystemFont::Iterator it(fontList);
69 for ( ; it.More(); it.Next() ) {
70 OGLFont_SysInfo* info = new OGLFont_SysInfo();
71 if ( it.Value()->FontAspect() == OSD_FA_Regular ) {
72 //this workaround for fonts with names dependent on system locale.
73 //for example: "Times New Roman Fett Kursive" or "Times New Roman Gras Italiqui"
74 FTFace face(it.Value()->FontPath()->ToCString());
75
76 if ( face.Error() == FT_Err_Ok ) {
77 if ( (*face.Face())->style_flags == 0 ) {
78 info->SysFont = it.Value();
79 }
80 else {
81 //new aspect detected for current font item
82#ifdef TRACE
83 cout << "TKOpenGl::initializeFontDB() detected new font!\n"
84 << "\tFont Previous Name: " << it.Value()->FontName()->ToCString() << endl
85 << "\tFont New Name: " << (*face.Face())->family_name << endl
86 << "\tFont Aspect: " << (*face.Face())->style_flags << endl;
87#endif
88 OSD_FontAspect aspect = OSD_FA_Regular;
89 if ( (*face.Face())->style_flags == (FT_STYLE_FLAG_ITALIC | FT_STYLE_FLAG_BOLD) )
90 aspect = OSD_FA_BoldItalic;
91 else if ( (*face.Face())->style_flags == FT_STYLE_FLAG_ITALIC )
92 aspect = OSD_FA_Italic;
93 else if ( (*face.Face())->style_flags == FT_STYLE_FLAG_BOLD )
94 aspect = OSD_FA_Bold;
95
96#ifdef TRACE
97 cout << "\tOSD_FontAspect: " << aspect << endl;
98#endif
99 Handle(TCollection_HAsciiString) aFontName =
100 new TCollection_HAsciiString( (*face.Face())->family_name );
101 info->SysFont = new OSD_SystemFont( aFontName, aspect, it.Value()->FontPath() );
102 }
103 }
104 else
105 continue;
106 } else {
107 info->SysFont = it.Value();
108 }
109 _FontDB.Append(info);
110
111 }
112 }
113 }
114
115#ifdef TRACE
116 if ( !_FontDB.Size() ) {
117 cout << "\nTKOpenGl::initializeFontDB() FAILED!!!\n"
118 << "No fonts detected in the system!\n"
119 << "Text rendering in 3D viewer will not be available." << endl;
120 }
121#endif
122}
123
124bool OpenGl_FontMgr::requestFontList( Graphic3d_NListOfHAsciiString& lst)
125{
126 FontDBIt DBit(_FontDB);
127 lst.Clear();
128 for ( ; DBit.More(); DBit.Next() ) {
129 lst.Append( DBit.Value()->SysFont->FontName() );
130 }
131 return true;
132}
133
134// Empty fontName means that ANY family name can be used.
135// fontAspect == OSD_FA_Undefined means ANY font aspect is acceptable.
136// fontheight == -1 means ANY font height is acceptable.
137int OpenGl_FontMgr::request_font( const Handle(TCollection_HAsciiString)& fontName,
138 const OSD_FontAspect fontAspect,
139 const Standard_Integer fontHeight )
140{
141 Standard_Integer aFontHeight = fontHeight;
142 if ( aFontHeight < 2 && aFontHeight != -1 )
143 {
144#ifdef TRACE
145 cout << "TKOpenGl::request_font\n"
146 << " Error: font height is invalid!!!\n"
147 << " font height:" << aFontHeight << "\n";
148#endif //TRACE
149 return -1;
150 }
151
152#ifdef TRACE
153 cout << "TKOpenGl::request_font\n"
154 << " font name: " << fontName->ToCString() << endl
155 << " font aspect: " << fontAspect << endl
156 << " font height: " << aFontHeight << endl;
157#endif
158
159 GLCONTEXT ctx = GET_GL_CONTEXT();
160
161 //check for font
162 FontDBIt DBit(_FontDB);
163
164#ifdef TRACE
165 cout << "Searching font in font database...\n";
166#endif
167
168 for ( ; DBit.More(); DBit.Next() ) {
169 // san (23.07.2010): comparing font names in case-insensitive mode,
170 // as on SUN and SGI system font names are in lower-case
171 if ( fontName->IsEmpty() || DBit.Value()->SysFont->FontName()->IsSameString(fontName, Standard_False) ) {
172#ifdef TRACE
173 cout << "\tName is found...\n\tCheking aspect...\n";
174#endif
175
176 //check for font aspect
177 if (fontAspect != OSD_FA_Undefined && DBit.Value()->SysFont->FontAspect() != fontAspect) {
178#ifdef TRACE
179 cout << "\tAspect of candidate font: " << DBit.Value()->SysFont->FontAspect() << endl;
180 cout << "\tAspects are not equal! Continue seaching...\n";
181#endif
182 continue;
183 }
184
185#ifdef TRACE
186 cout << "\tAspect is found...\n\tCheking height...\n";
187#endif
188 //check for fixed height
189 if (DBit.Value()->SysFont->FontHeight() != -1) {
190#ifdef TRACE
191 cout << "\tChecking fixed height: " << DBit.Value()->SysFont->FontHeight() << endl;
192#endif
193 //fixed height font
194 if ( aFontHeight != -1 && DBit.Value()->SysFont->FontHeight() != aFontHeight ){
195#ifdef TRACE
196 cout << "\tHeights are not equal! Continue seaching...\n";
197#endif
198 continue;
199 }
200 else
201 {
202 // We need to remember the font height to be used
203 if ( aFontHeight == -1 )
204 aFontHeight = DBit.Value()->SysFont->FontHeight();
205#ifdef TRACE
206 cout << "\tHeight is found\n";
207#endif
208 }
209 }
210 else
211 {
212 // If font height is not specified -> use DEFAULT_FONT_HEIGHT for variable-height fonts
213 if ( aFontHeight == -1 )
214 aFontHeight = DEFAULT_FONT_HEIGHT;
215#ifdef TRACE
216 cout << "\tFont has variable height == -1. height is found\n";
217#endif
218 }
219#ifdef TRACE
220 cout << "\tChecking font manager cache...\n";
221#endif
222 //check in loaded fonts
223 IDList::Iterator fIt(DBit.Value()->GeneratedFonts);
224 for ( ; fIt.More(); fIt.Next() ) {
225 OGLFont_Cache cache = _FontCache.Find( fIt.Value() );
226 if ( cache.FontHeight == aFontHeight && cache.GlContext == ctx ) {
227 //requested font is generated already
228
229#ifdef TRACE
230 cout << "\tRequested font is generated already\n\tId = " ;
231 cout << fIt.Value() << endl;
232#endif
233 _CurrentFontId = fIt.Value();
234 return _CurrentFontId;
235 } else {
236#ifdef TRACE
237 cout << "\t\tHeights or contexts are not equal:\n"
238 << "\t\t\tfont height: " << aFontHeight << "\tchache height: " << cache.FontHeight << endl
239 << "\t\t\tfont context: " << ctx << "\tchache context: " << cache.GlContext << endl;
240 cout << "\t\tContinue searching in cache...\n";
241#endif
242 }
243 }
244#ifdef TRACE
245 cout << "\tRequested font is not found among genarated fonts.\n\tCreating new...\n";
246#endif
247 //if not found in generated fonts
248 //create new
249 FTGLTextureFont* font = new FTGLTextureFont(DBit.Value()->SysFont->FontPath()->ToCString());
250 //by default creates regular font
251 if ( ! font || font->Error() != FT_Err_Ok) {
252#ifdef TRACE
253 cout << "\t\tError during creation FTGL font object!\n";
254#endif
255 return -1;
256 }
257
258 if ( ! font->FaceSize( aFontHeight) || font->Error() != FT_Err_Ok ){
259#ifdef TRACE
260 cout << "\t\tError during setup FTGL font height!\n";
261#endif
262 return -1;
263 }
264 font->UseDisplayList( false );
265
266 //put font to cache
267 OGLFont_Cache cache;
268 cache.Font = font;
269 cache.FontHeight = aFontHeight;
270 cache.GlContext = ctx;
271
272 _CurrentFontId =_FontCache.Size() + 1;
273 _FontCache.Bind( _CurrentFontId, cache );
274 DBit.Value()->GeneratedFonts.Append(_CurrentFontId);
275
276#ifdef TRACE
277 cout << "TKOpenGl::Loaded New FTGL font:\n"
278 << " font name: " << fontName->ToCString() << "\n"
279 << " font aspect: ";
280
281 switch( fontAspect )
282 {
283 case OSD_FA_Bold:
284 cout << "OSD_FA_Bold\n";
285 break;
286 case OSD_FA_BoldItalic:
287 cout << "OSD_FA_BoldItalic\n";
288 break;
289 case OSD_FA_Italic:
290 cout << "OSD_FA_Italic\n";
291 break;
292 case OSD_FA_Regular:
293 cout << "OSD_FA_Regular\n";
294 break;
295 default:
296 cout << "OSD_FA_Undefined\n";
297 break;
298 }
299 cout << " font height: "<<aFontHeight<<"\n";
300 cout << " font id: " << _CurrentFontId << "\n";
301#endif
302
303 return _CurrentFontId;
304 }
305 }
306 //invalid family name
307#ifdef TRACE
308 cout << "\n---Invalid Family Name!!!---\n";
309#endif
310 return -1;
311}
312
256d4320
A
313void OpenGl_FontMgr::render_text( const Standard_Integer id, const char* text,
314 const Standard_Boolean is2d )
7fd59977 315{
316#ifdef TRACE
317 cout << "TKOpenGl::render_text\n"
318 << "\tfont id = " << id << endl
319 << "\ttext = " << text << endl;
320#endif
321 if ( text && _FontCache.IsBound( id ) ) {
322 glMatrixMode( GL_MODELVIEW );
323 glPushMatrix();
324
325 glScalef( _XCurrentScale, _YCurrentScale, 1 );
326 glPushAttrib( GL_ENABLE_BIT );
327
328 GLboolean enableTexture = glIsEnabled(GL_TEXTURE_2D);
329 GLboolean enableDepthTest = glIsEnabled(GL_DEPTH_TEST);
330
331 if( !enableTexture )
332 glEnable(GL_TEXTURE_2D);
256d4320
A
333 if ( !is2d ) {
334 if ( !enableDepthTest )
335 glEnable(GL_DEPTH_TEST);
336 }
337 else if ( enableDepthTest ) {
338 glDisable(GL_DEPTH_TEST);
339 }
7fd59977 340
341 GLint* param = new GLint;
342 glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, param);
343
344 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
345 glAlphaFunc(GL_GEQUAL, 0.285f);
346 glEnable(GL_ALPHA_TEST);
347 OGLFont_Cache cache = _FontCache.Find( id );
348 cache.Font->Render( text );
349
350 glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, *param);
351
352 if( !enableTexture )
353 glDisable(GL_TEXTURE_2D);
354 if( !enableDepthTest )
355 glDisable(GL_DEPTH_TEST);
356
357 delete param;
358
359 glPopAttrib();
360 glMatrixMode( GL_MODELVIEW );
361 glPopMatrix();
362 }
363
364}
365
256d4320
A
366void OpenGl_FontMgr::render_text( const char* text, const Standard_Boolean is2d ){
367 render_text( _CurrentFontId, text, is2d );
7fd59977 368}
369
370
371const FTFont* OpenGl_FontMgr::fontById( const Standard_Integer id ){
372 return _FontCache.IsBound( id ) ? _FontCache.Find( id ).Font: NULL;
373}
374
375Standard_ShortReal OpenGl_FontMgr::computeWidth( const Standard_Integer id, const char* str ){
376 if( !_FontCache.IsBound( id ) )
377 return 0.f;
378
379 OGLFont_Cache cache = _FontCache.Find( id );
7fd59977 380
381 Standard_ShortReal w = cache.Font->Advance( str );
382
383 return w;
384}
385
386void OpenGl_FontMgr::setCurrentScale( const Standard_ShortReal xScale,
387 const Standard_ShortReal yScale)
388{
389 _XCurrentScale = xScale;
390 _YCurrentScale = yScale;
391}
392
393#include <AlienImage_BMPAlienData.hxx>
394#include <OSD_File.hxx>
395#include <OSD_Protection.hxx>
396#include <Aspect_GenericColorMap.hxx>
397#include <Image_ColorImage.hxx>
398#include <Quantity_Color.hxx>
399
400void dump_texture( int id) {
401 Handle(AlienImage_BMPAlienData) image = new AlienImage_BMPAlienData();
402
403 if (!glIsTexture(id))
404 return;
405
406 unsigned char* pixels = new unsigned char[8192*1024];
407 memset( pixels, 0, 8192*1024 );
408 static int index = 0;
409 index++;
410
411 glBindTexture(GL_TEXTURE_2D, id );
412 glGetTexImage( GL_TEXTURE_2D ,
413 0,
414 GL_ALPHA,
415 GL_UNSIGNED_BYTE,
416 pixels );
417
418 Handle(Image_ColorImage) anImage = new Image_ColorImage( 0, 0, 1024, 8192 );
419
420 Aspect_ColorPixel mark( Quantity_Color (0.,0.5,1., Quantity_TOC_RGB ) ),
421 space( Quantity_Color (1.,1.,1., Quantity_TOC_RGB ) );
422
423 for( int i = 0; i < 1024; i++ ) {
424 for (int j = 0; j < 8192; j++ )
425 if (pixels[i*8192+j]>0) {
426 anImage->SetPixel( anImage->LowerX()+i,
427 anImage->LowerY()+j,
428 mark );
429 }
430 else {
431 anImage->SetPixel( anImage->LowerX()+i,
432 anImage->LowerY()+j,
433 space );
434 }
435 }
436
437 image->FromImage( anImage );
438 TCollection_AsciiString name( index );
439 name.Prepend( "D:\\Temp_image" );
440 name += ".bmp";
441 OSD_File file ( name );
442 file.Build( OSD_WriteOnly, OSD_Protection());
443 image->Write(file);
444 file.Close();
445 delete []pixels;
446}