0023415: OSD_FontMgr can't idenify aspect for fonts with names dependant on system...
[occt.git] / src / OpenGl / OpenGl_FontMgr.cxx
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
18 #include <OpenGl_FontMgr.hxx>
19 #include <OpenGl_GlCore11.hxx>
20
21 #include <Standard_Stream.hxx>
22 #include <TColStd_SequenceOfHAsciiString.hxx>
23
24 #ifdef _MSC_VER
25 #pragma comment( lib, "ftgl.lib" )
26 #endif
27
28 #undef TRACE
29
30 #define DEFAULT_FONT_HEIGHT 16
31
32 float h_scale = 0;
33
34 void dump_texture( int id);
35
36 class Font_DataMap:
37   public NCollection_DataMap< Handle(TCollection_HAsciiString),
38   Handle(TCollection_HAsciiString)>
39 {
40 public:
41   inline Font_DataMap
42     (const Standard_Integer NbBuckets = 1,
43     const Handle(NCollection_BaseAllocator)& theAllocator = 0L)
44     :  NCollection_DataMap<Handle(TCollection_HAsciiString),
45     Handle(TCollection_HAsciiString)> (NbBuckets, theAllocator)
46   {}
47
48   inline Font_DataMap (const Font_DataMap& theOther)
49     :  NCollection_DataMap<Handle(TCollection_HAsciiString),
50     Handle(TCollection_HAsciiString)> (theOther)
51   {}  
52   friend Standard_Boolean IsEqual( const Handle(TCollection_HAsciiString)& h1,
53     const Handle(TCollection_HAsciiString)& h2 );
54 };
55 inline Standard_Boolean
56 IsEqual( const Handle(TCollection_HAsciiString)& h1,
57         const Handle(TCollection_HAsciiString)& h2 )
58 {
59   return (!h1->IsLess(h2) && !h1->IsGreater(h2));
60 }
61
62 OpenGl_FontMgr::OpenGl_FontMgr()
63 : myCurrentFontId(-1),
64 myXCurrentScale(1.f),
65 myYCurrentScale(1.f) 
66 {
67 }
68
69 OpenGl_FontMgr* OpenGl_FontMgr::instance() 
70 {
71   static OpenGl_FontMgr* _mgr = NULL;
72   if ( _mgr == NULL )
73   {
74     _mgr = new OpenGl_FontMgr();
75   }
76   return _mgr;
77 }
78
79 // Empty fontName means that ANY family name can be used.
80 // fontAspect == Font_FA_Undefined means ANY font aspect is acceptable.
81 // fontheight == -1 means ANY font height is acceptable.
82 int OpenGl_FontMgr::request_font (const Handle(TCollection_HAsciiString)& theFontName,
83                                   const Font_FontAspect                   theFontAspect,
84                                   const Standard_Integer&                 theFontHeight)
85 {
86   Handle(Font_FontMgr) aFontMgr = Font_FontMgr::GetInstance();
87   Handle(Font_SystemFont) aRequestedFont = aFontMgr->FindFont (theFontName, theFontAspect, theFontHeight);
88
89   if (aRequestedFont.IsNull())
90   {
91     return -1;
92   }
93
94   // Setting font height
95   Standard_Integer aFontHeight = theFontHeight;
96   if (theFontHeight < 2 && aRequestedFont->FontHeight() == -1)
97   {
98     // Font height is not specified -> use DEFAULT_FONT_HEIGHT for variable-height fonts
99     aFontHeight = DEFAULT_FONT_HEIGHT;
100   }
101   else if (theFontHeight < 2)
102   {
103     // Font height is not specified -> use font height for fixed size fonts
104     aFontHeight = aRequestedFont->FontHeight();
105   }
106
107   GLCONTEXT aContext = GET_GL_CONTEXT();
108
109   // Check in already generated fonts.
110   if (myGeneratedFontDB.IsBound (aRequestedFont))
111   {
112     const IDList& anIDList = myGeneratedFontDB.Find (aRequestedFont);
113     for (IDList::Iterator anIDListIterator (anIDList); anIDListIterator.More();
114          anIDListIterator.Next())
115     {
116       OGLFont_Cache aFontCache = myGeneratedFontCache (anIDListIterator.Value());
117       if (aFontCache.FontHeight == aFontHeight && aFontCache.GlContext == aContext)
118       {
119         // Requested font is already generated, returning it cache ID.
120         myCurrentFontId = anIDListIterator.Value();
121         return myCurrentFontId;
122       }
123     }
124   }
125
126   // Cache for requested font is not found. Generating new FTGL font.
127   FTGLTextureFont* aFTGLFont = new FTGLTextureFont(aRequestedFont->FontPath()->ToCString());
128   if ( !aFTGLFont || aFTGLFont->Error() != FT_Err_Ok)
129   {
130     return -1; // Error during creation FTGL font object!
131   }
132
133   if ( !aFTGLFont->FaceSize (aFontHeight) || aFTGLFont->Error() != FT_Err_Ok )
134   {
135     return -1; // Error during setup FTGL font height!
136   }
137
138   aFTGLFont->UseDisplayList (false);
139
140   // Adding font to cache.
141   OGLFont_Cache aCache;
142   aCache.Font = aFTGLFont;
143   aCache.FontHeight = aFontHeight;
144   aCache.GlContext = aContext;
145
146   myCurrentFontId = myGeneratedFontCache.Size() + 1;
147   myGeneratedFontCache.Bind ( myCurrentFontId, aCache);
148
149   if (myGeneratedFontDB.IsBound (aRequestedFont))
150   {
151     myGeneratedFontDB.ChangeFind (aRequestedFont).Append (myCurrentFontId);
152   }
153   else
154   {
155     IDList anIDList;
156     anIDList.Append (myCurrentFontId);
157     myGeneratedFontDB.Bind (aRequestedFont, anIDList);
158   }
159
160   return myCurrentFontId;
161 }
162
163 void OpenGl_FontMgr::render_text( const Standard_Integer id, const wchar_t* text,
164                                   const Standard_Boolean is2d )
165 {
166 #ifdef TRACE
167   cout << "TKOpenGl::render_text\n"
168     << "\tfont id = " << id << endl
169     << "\ttext = " << text << endl;
170 #endif
171   if ( text && myGeneratedFontCache.IsBound( id ) ) {
172     glMatrixMode( GL_MODELVIEW );
173     glPushMatrix();
174
175     glScalef( myXCurrentScale, myYCurrentScale, 1 );
176     glPushAttrib( GL_ENABLE_BIT );
177
178     GLboolean enableTexture = glIsEnabled(GL_TEXTURE_2D);
179     GLboolean enableDepthTest = glIsEnabled(GL_DEPTH_TEST);
180
181     if( !enableTexture )
182       glEnable(GL_TEXTURE_2D);
183     if ( !is2d ) {
184       if ( !enableDepthTest )
185         glEnable(GL_DEPTH_TEST);
186     }
187     else if ( enableDepthTest ) {
188         glDisable(GL_DEPTH_TEST);
189     }
190
191     GLint param;
192     glGetTexEnviv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &param);
193
194     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); 
195     glAlphaFunc(GL_GEQUAL, 0.285f);    
196     glEnable(GL_ALPHA_TEST);   
197     OGLFont_Cache cache = myGeneratedFontCache.Find( id );
198     cache.Font->Render( text );
199
200     glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, param);
201
202     if( !enableTexture )
203       glDisable(GL_TEXTURE_2D);
204     if( !enableDepthTest )
205       glDisable(GL_DEPTH_TEST);
206
207     glPopAttrib();
208     glMatrixMode( GL_MODELVIEW );
209     glPopMatrix();
210   }
211
212 }
213
214 void OpenGl_FontMgr::render_text ( const wchar_t* text, const Standard_Boolean is2d )
215 {
216   render_text( myCurrentFontId, text, is2d );
217 }
218
219 const FTFont* OpenGl_FontMgr::fontById (const Standard_Integer id)
220 {
221   return myGeneratedFontCache.IsBound( id ) ? myGeneratedFontCache.Find( id ).Font: NULL;
222 }
223
224 Standard_ShortReal OpenGl_FontMgr::computeWidth( const Standard_Integer id, const wchar_t* text )
225 {
226   if( !myGeneratedFontCache.IsBound( id ) )
227     return 0.f;
228
229   OGLFont_Cache cache = myGeneratedFontCache.Find( id );
230
231   Standard_ShortReal w = cache.Font->Advance( text );
232
233   return w;
234 }
235
236 void OpenGl_FontMgr::setCurrentScale (const Standard_ShortReal xScale,
237                                       const Standard_ShortReal yScale)
238 {
239   myXCurrentScale = xScale;
240   myYCurrentScale = yScale;
241 }
242
243 #include <AlienImage_BMPAlienData.hxx>
244 #include <OSD_File.hxx>
245 #include <OSD_Protection.hxx>
246 #include <Aspect_GenericColorMap.hxx>
247 #include <Image_ColorImage.hxx>
248 #include <Quantity_Color.hxx>
249
250 void dump_texture( int id)
251 {
252   Handle(AlienImage_BMPAlienData) image = new AlienImage_BMPAlienData();
253
254   if (!glIsTexture(id))
255     return;
256
257   unsigned char* pixels = new unsigned char[8192*1024];
258   memset( pixels, 0, 8192*1024 );
259   static int index = 0;
260   index++;
261
262   glBindTexture(GL_TEXTURE_2D, id );
263   glGetTexImage( GL_TEXTURE_2D , 
264     0,
265     GL_ALPHA,
266     GL_UNSIGNED_BYTE,
267     pixels );
268
269   Handle(Image_ColorImage) anImage = new Image_ColorImage( 0, 0, 1024, 8192 );
270
271   Aspect_ColorPixel mark( Quantity_Color (0.,0.5,1., Quantity_TOC_RGB ) ),
272     space( Quantity_Color (1.,1.,1., Quantity_TOC_RGB ) );
273
274   for( int i = 0; i < 1024; i++ ) {
275     for (int j = 0; j < 8192; j++ )
276       if (pixels[i*8192+j]>0) {
277         anImage->SetPixel( anImage->LowerX()+i, 
278           anImage->LowerY()+j,
279           mark );
280       }
281       else {
282         anImage->SetPixel( anImage->LowerX()+i, 
283           anImage->LowerY()+j,
284           space );
285       }
286   }
287
288   image->FromImage( anImage );
289   TCollection_AsciiString name( index );
290   name.Prepend( "D:\\Temp_image" );
291   name += ".bmp";
292   OSD_File file ( name );
293   file.Build( OSD_WriteOnly, OSD_Protection());
294   image->Write(file);
295   file.Close();
296   delete []pixels;
297 }