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> |
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 | ||
29 | float h_scale = 0; | |
30 | ||
31 | void dump_texture( int id); | |
32 | ||
33 | class Font_DataMap: | |
34 | public NCollection_DataMap< Handle(TCollection_HAsciiString), | |
35 | Handle(TCollection_HAsciiString)> | |
36 | { | |
37 | public: | |
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 | }; | |
52 | inline Standard_Boolean | |
53 | IsEqual( const Handle(TCollection_HAsciiString)& h1, | |
54 | const Handle(TCollection_HAsciiString)& h2 ) | |
55 | { | |
56 | return (!h1->IsLess(h2) && !h1->IsGreater(h2)); | |
57 | } | |
58 | ||
59 | OpenGl_FontMgr::OpenGl_FontMgr() | |
60 | : _CurrentFontId(-1), | |
61 | _XCurrentScale(1.f), | |
62 | _YCurrentScale(1.f) | |
63 | { | |
64 | } | |
65 | ||
66 | OpenGl_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 | ||
77 | void 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 | ||
141 | bool 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. | |
154 | int 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 |
330 | void 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, ¶m); | |
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 |
381 | void 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 |
386 | const FTFont* OpenGl_FontMgr::fontById (const Standard_Integer id) |
387 | { | |
7fd59977 | 388 | return _FontCache.IsBound( id ) ? _FontCache.Find( id ).Font: NULL; |
389 | } | |
390 | ||
13a22457 S |
391 | Standard_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 |
403 | void 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 |
417 | void 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 | } |