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