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