Commit | Line | Data |
---|---|---|
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 | ||
34 | float h_scale = 0; | |
35 | ||
36 | void dump_texture( int id); | |
37 | ||
38 | class Font_DataMap: | |
39 | public NCollection_DataMap< Handle(TCollection_HAsciiString), | |
40 | Handle(TCollection_HAsciiString)> | |
41 | { | |
42 | public: | |
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 | }; | |
57 | inline Standard_Boolean | |
58 | IsEqual( const Handle(TCollection_HAsciiString)& h1, | |
59 | const Handle(TCollection_HAsciiString)& h2 ) | |
60 | { | |
61 | return (!h1->IsLess(h2) && !h1->IsGreater(h2)); | |
62 | } | |
63 | ||
64 | OpenGl_FontMgr::OpenGl_FontMgr() | |
65 | : _CurrentFontId(-1), | |
66 | _XCurrentScale(1.f), | |
67 | _YCurrentScale(1.f) | |
68 | { | |
69 | } | |
70 | ||
71 | OpenGl_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 | ||
82 | void 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 | ||
166 | bool 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. |
179 | int 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 |
355 | void 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, ¶m); | |
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 |
406 | void 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 |
411 | const FTFont* OpenGl_FontMgr::fontById (const Standard_Integer id) |
412 | { | |
7fd59977 | 413 | return _FontCache.IsBound( id ) ? _FontCache.Find( id ).Font: NULL; |
414 | } | |
415 | ||
13a22457 S |
416 | Standard_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 |
428 | void 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 |
442 | void 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 | } |