0023842: Undefined behavior: Variable 'thePsFont' is used as parameter and destinatio...
[occt.git] / src / OpenGl / OpenGl_Text.cxx
1 // Created on: 2011-07-13
2 // Created by: Sergey ZERCHANINOV
3 // Copyright (c) 2011-2013 OPEN CASCADE SAS
4 //
5 // The content of this file is subject to the Open CASCADE Technology Public
6 // License Version 6.5 (the "License"). You may not use the content of this file
7 // except in compliance with the License. Please obtain a copy of the License
8 // at http://www.opencascade.org and read it completely before using this file.
9 //
10 // The Initial Developer of the Original Code is Open CASCADE S.A.S., having its
11 // main offices at: 1, place des Freres Montgolfier, 78280 Guyancourt, France.
12 //
13 // The Original Code and all software distributed under the License is
14 // distributed on an "AS IS" basis, without warranty of any kind, and the
15 // Initial Developer hereby disclaims all such warranties, including without
16 // limitation, any warranties of merchantability, fitness for a particular
17 // purpose or non-infringement. Please see the License for the specific terms
18 // and conditions governing the rights and limitations under the License.
19
20 #include <OpenGl_GlCore11.hxx>
21 #include <OpenGl_Text.hxx>
22
23 #include <OpenGl_AspectText.hxx>
24 #include <OpenGl_GraphicDriver.hxx>
25 #include <OpenGl_Workspace.hxx>
26
27 #include <Font_FontMgr.hxx>
28 #include <TCollection_HAsciiString.hxx>
29
30 #ifdef HAVE_CONFIG_H
31   #include <config.h>
32 #endif
33
34 #ifdef HAVE_GL2PS
35   #include <gl2ps.h>
36 #endif
37
38 namespace
39 {
40   static const GLdouble THE_IDENTITY_MATRIX[4][4] =
41   {
42     {1.,0.,0.,0.},
43     {0.,1.,0.,0.},
44     {0.,0.,1.,0.},
45     {0.,0.,0.,1.}
46   };
47
48 #ifdef HAVE_GL2PS
49   static char const* TheFamily[] = {"Helvetica", "Courier", "Times"};
50   static char const* TheItalic[] = {"Oblique",   "Oblique", "Italic"};
51   static char const* TheBase[]   = {"", "", "-Roman"};
52
53   //! Convert font name used for rendering to some "good" font names
54   //! that produce good vector text.
55   static void getGL2PSFontName (const char* theSrcFont,
56                                 char*       thePsFont)
57   {
58     if (strstr (theSrcFont, "Symbol"))
59     {
60       sprintf (thePsFont, "%s", "Symbol");
61       return;
62     }
63     else if (strstr (theSrcFont, "ZapfDingbats"))
64     {
65       sprintf (thePsFont, "%s", "WingDings");
66       return;
67     }
68
69     int  aFontId  = 0;
70     bool isBold   = false;
71     bool isItalic = false;
72     if (strstr (theSrcFont, "Courier"))
73     {
74       aFontId = 1;
75     }
76     else if (strstr (theSrcFont, "Times"))
77     {
78       aFontId = 2;
79     }
80
81     if (strstr (theSrcFont, "Bold"))
82     {
83       isBold = true;
84     }
85     if (strstr (theSrcFont, "Italic")
86      || strstr (theSrcFont, "Oblique"))
87     {
88       isItalic = true;
89     }
90
91     if (isBold)
92     {
93       if (isItalic)
94       {
95         sprintf (thePsFont, "%s-Bold%s", TheFamily[aFontId], TheItalic[aFontId]);
96       }
97       else
98       {
99         sprintf (thePsFont, "%s-Bold", TheFamily[aFontId]);
100       }
101     }
102     else if (isItalic)
103     {
104       sprintf (thePsFont, "%s-%s", TheFamily[aFontId], TheItalic[aFontId]);
105     }
106     else
107     {
108       sprintf (thePsFont, "%s%s", TheFamily[aFontId], TheBase[aFontId]);
109     }
110   }
111
112   static void exportText (const NCollection_String& theText,
113                           const Standard_Boolean    theIs2d,
114                           const OpenGl_AspectText&  theAspect,
115                           const Standard_Integer    theHeight)
116   {
117
118     char aPsFont[64];
119     getGL2PSFontName (theAspect.FontName().ToCString(), aPsFont);
120
121     if (theIs2d)
122     {
123       glRasterPos2f (0.0f, 0.0f);
124     }
125     else
126     {
127       glRasterPos3f (0.0f, 0.0f, 0.0f);
128     }
129
130     GLubyte aZero = 0;
131     glBitmap (1, 1, 0, 0, 0, 0, &aZero);
132
133     // Standard GL2PS's alignment isn't used, because it doesn't work correctly
134     // for all formats, therefore alignment is calculated manually relative
135     // to the bottom-left corner, which corresponds to the GL2PS_TEXT_BL value
136     gl2psTextOpt (theText.ToCString(), aPsFont, theHeight, GL2PS_TEXT_BL, theAspect.Angle());
137   }
138 #endif
139
140 };
141
142 // =======================================================================
143 // function : OpenGl_Text
144 // purpose  :
145 // =======================================================================
146 OpenGl_Text::OpenGl_Text()
147 : myWinX (0.0f),
148   myWinY (0.0f),
149   myWinZ (0.0f),
150   myScaleHeight (1.0f),
151   myPoint  (0.0f, 0.0f, 0.0f),
152   myIs2d   (false)
153 {
154   myParams.Height = 10;
155   myParams.HAlign = Graphic3d_HTA_LEFT;
156   myParams.VAlign = Graphic3d_VTA_BOTTOM;
157 }
158
159 // =======================================================================
160 // function : OpenGl_Text
161 // purpose  :
162 // =======================================================================
163 OpenGl_Text::OpenGl_Text (const TCollection_ExtendedString& theText,
164                           const OpenGl_Vec3&                thePoint,
165                           const OpenGl_TextParam&           theParams)
166 : myWinX (0.0f),
167   myWinY (0.0f),
168   myWinZ (0.0f),
169   myScaleHeight  (1.0f),
170   myExportHeight (1.0f),
171   myParams (theParams),
172   myString ((Standard_Utf16Char* )theText.ToExtString()),
173   myPoint  (thePoint),
174   myIs2d   (false)
175 {
176   //
177 }
178
179 // =======================================================================
180 // function : SetPosition
181 // purpose  :
182 // =======================================================================
183 void OpenGl_Text::SetPosition (const OpenGl_Vec3& thePoint)
184 {
185   myPoint = thePoint;
186 }
187
188 // =======================================================================
189 // function : SetFontSize
190 // purpose  :
191 // =======================================================================
192 void OpenGl_Text::SetFontSize (const Handle(OpenGl_Context)& theCtx,
193                                const Standard_Integer        theFontSize)
194 {
195   if (myParams.Height != theFontSize)
196   {
197     Release (theCtx);
198   }
199   myParams.Height = theFontSize;
200 }
201
202 // =======================================================================
203 // function : Init
204 // purpose  :
205 // =======================================================================
206 void OpenGl_Text::Init (const Handle(OpenGl_Context)& theCtx,
207                         const Standard_Utf8Char*      theText,
208                         const OpenGl_Vec3&            thePoint)
209 {
210   releaseVbos (theCtx);
211   myIs2d   = false;
212   myPoint  = thePoint;
213   myString.FromUnicode (theText);
214 }
215
216 // =======================================================================
217 // function : Init
218 // purpose  :
219 // =======================================================================
220 void OpenGl_Text::Init (const Handle(OpenGl_Context)& theCtx,
221                         const Standard_Utf8Char*      theText,
222                         const OpenGl_Vec3&            thePoint,
223                         const OpenGl_TextParam&       theParams)
224 {
225   if (myParams.Height != theParams.Height)
226   {
227     Release (theCtx);
228   }
229   else
230   {
231     releaseVbos (theCtx);
232   }
233   myIs2d   = false;
234   myParams = theParams;
235   myPoint  = thePoint;
236   myString.FromUnicode (theText);
237 }
238
239 // =======================================================================
240 // function : Init
241 // purpose  :
242 // =======================================================================
243 void OpenGl_Text::Init (const Handle(OpenGl_Context)&     theCtx,
244                         const TCollection_ExtendedString& theText,
245                         const OpenGl_Vec2&                thePoint,
246                         const OpenGl_TextParam&           theParams)
247 {
248   if (myParams.Height != theParams.Height)
249   {
250     Release (theCtx);
251   }
252   else
253   {
254     releaseVbos (theCtx);
255   }
256   myIs2d       = true;
257   myParams     = theParams;
258   myPoint.xy() = thePoint;
259   myPoint.z()  = 0.0f;
260   myString.FromUnicode ((Standard_Utf16Char* )theText.ToExtString());
261 }
262
263 // =======================================================================
264 // function : ~OpenGl_Text
265 // purpose  :
266 // =======================================================================
267 OpenGl_Text::~OpenGl_Text()
268 {
269   //
270 }
271
272 // =======================================================================
273 // function : releaseVbos
274 // purpose  :
275 // =======================================================================
276 void OpenGl_Text::releaseVbos (const Handle(OpenGl_Context)& theCtx)
277 {
278   for (Standard_Integer anIter = 0; anIter < myVertsVbo.Length(); ++anIter)
279   {
280     Handle(OpenGl_VertexBuffer)& aVerts = myVertsVbo.ChangeValue (anIter);
281     Handle(OpenGl_VertexBuffer)& aTCrds = myTCrdsVbo.ChangeValue (anIter);
282
283     if (!theCtx.IsNull())
284     {
285       theCtx->DelayedRelease (aVerts);
286       theCtx->DelayedRelease (aTCrds);
287     }
288     aVerts.Nullify();
289     aTCrds.Nullify();
290   }
291   myTextures.Clear();
292   myVertsVbo.Clear();
293   myTCrdsVbo.Clear();
294   myVertsArray.Clear();
295   myTCrdsArray.Clear();
296 }
297
298 // =======================================================================
299 // function : Release
300 // purpose  :
301 // =======================================================================
302 void OpenGl_Text::Release (const Handle(OpenGl_Context)& theCtx)
303 {
304   releaseVbos (theCtx);
305   if (!myFont.IsNull())
306   {
307     Handle(OpenGl_Context) aCtx = theCtx;
308     const TCollection_AsciiString aKey = myFont->ResourceKey();
309     myFont.Nullify();
310     aCtx->ReleaseResource (aKey, Standard_True);
311   }
312 }
313
314 // =======================================================================
315 // function : StringSize
316 // purpose  :
317 // =======================================================================
318 void OpenGl_Text::StringSize (const Handle(OpenGl_Context)& theCtx,
319                               const NCollection_String&     theText,
320                               const OpenGl_AspectText&      theTextAspect,
321                               const OpenGl_TextParam&       theParams,
322                               Standard_ShortReal&           theWidth,
323                               Standard_ShortReal&           theAscent,
324                               Standard_ShortReal&           theDescent)
325 {
326   theWidth   = 0.0f;
327   theAscent  = 0.0f;
328   theDescent = 0.0f;
329   const TCollection_AsciiString aFontKey = FontKey (theTextAspect, theParams.Height);
330   Handle(OpenGl_Font) aFont = FindFont (theCtx, theTextAspect, theParams.Height, aFontKey);
331   if (aFont.IsNull() || !aFont->IsValid())
332   {
333     return;
334   }
335
336   theAscent  = aFont->Ascender();
337   theDescent = aFont->Descender();
338
339   GLfloat aWidth = 0.0f;
340   for (NCollection_Utf8Iter anIter = theText.Iterator(); *anIter != 0;)
341   {
342     const Standard_Utf32Char aCharThis =   *anIter;
343     const Standard_Utf32Char aCharNext = *++anIter;
344
345     if (aCharThis == '\x0D' // CR  (carriage return)
346      || aCharThis == '\a'   // BEL (alarm)
347      || aCharThis == '\f'   // FF  (form feed) NP (new page)
348      || aCharThis == '\b'   // BS  (backspace)
349      || aCharThis == '\v')  // VT  (vertical tab)
350     {
351       continue; // skip unsupported carriage control codes
352     }
353     else if (aCharThis == '\x0A') // LF (line feed, new line)
354     {
355       theWidth = Max (theWidth, aWidth);
356       aWidth   = 0.0f;
357       continue;
358     }
359     else if (aCharThis == ' ')
360     {
361       aWidth += aFont->AdvanceX (aCharThis, aCharNext);
362       continue;
363     }
364     else if (aCharThis == '\t')
365     {
366       aWidth += aFont->AdvanceX (' ', aCharNext) * 8.0f;
367       continue;
368     }
369
370     aWidth += aFont->AdvanceX (aCharThis, aCharNext);
371   }
372   theWidth = Max (theWidth, aWidth);
373
374   Handle(OpenGl_Context) aCtx = theCtx;
375   aFont.Nullify();
376   aCtx->ReleaseResource (aFontKey, Standard_True);
377 }
378
379 // =======================================================================
380 // function : Render
381 // purpose  :
382 // =======================================================================
383 void OpenGl_Text::Render (const Handle(OpenGl_Workspace)& theWorkspace) const
384 {
385   if (theWorkspace->DegenerateModel > 0 && theWorkspace->SkipRatio >= 1.0f)
386   {
387     return;
388   }
389
390   const OpenGl_AspectText* aTextAspect = theWorkspace->AspectText (Standard_True);
391   const Handle(OpenGl_Texture) aPrevTexture = theWorkspace->DisableTexture();
392
393   // use highlight color or colors from aspect
394   if (theWorkspace->NamedStatus & OPENGL_NS_HIGHLIGHT)
395   {
396     render (theWorkspace->PrinterContext(),
397             theWorkspace->GetGlContext(),
398             *aTextAspect,
399             *theWorkspace->HighlightColor,
400             *theWorkspace->HighlightColor);
401   }
402   else
403   {
404     render (theWorkspace->PrinterContext(),
405             theWorkspace->GetGlContext(),
406             *aTextAspect,
407             aTextAspect->Color(),
408             aTextAspect->SubtitleColor());
409   }
410
411   // restore aspects
412   if (!aPrevTexture.IsNull())
413   {
414     theWorkspace->EnableTexture (aPrevTexture);
415   }
416 }
417
418 // =======================================================================
419 // function : Render
420 // purpose  :
421 // =======================================================================
422 void OpenGl_Text::Render (const Handle(OpenGl_PrinterContext)& thePrintCtx,
423                           const Handle(OpenGl_Context)&        theCtx,
424                           const OpenGl_AspectText&             theTextAspect) const
425 {
426   render (thePrintCtx, theCtx, theTextAspect, theTextAspect.Color(), theTextAspect.SubtitleColor());
427 }
428
429 // =======================================================================
430 // function : setupMatrix
431 // purpose  :
432 // =======================================================================
433 void OpenGl_Text::setupMatrix (const Handle(OpenGl_PrinterContext)& thePrintCtx,
434                                const Handle(OpenGl_Context)&        theCtx,
435                                const OpenGl_AspectText&             theTextAspect,
436                                const OpenGl_Vec3                    theDVec) const
437 {
438   // setup matrix
439   if (myIs2d)
440   {
441     glLoadIdentity();
442     glTranslatef (myPoint.x() + theDVec.x(), myPoint.y() + theDVec.y(), 0.0f);
443     glRotatef (180.0f, 1.0f, 0.0f, 0.0f);
444   }
445   else
446   {
447     // align coordinates to the nearest integer
448     // to avoid extra interpolation issues
449     GLdouble anObjX, anObjY, anObjZ;
450     gluUnProject (std::floor (myWinX + (GLdouble )theDVec.x()),
451                   std::floor (myWinY + (GLdouble )theDVec.y()),
452                   myWinZ + (GLdouble )theDVec.z(),
453                   (GLdouble* )THE_IDENTITY_MATRIX, myProjMatrix, myViewport,
454                   &anObjX, &anObjY, &anObjZ);
455
456     glLoadIdentity();
457     glTranslated (anObjX, anObjY, anObjZ);
458     glRotated (theTextAspect.Angle(), 0.0, 0.0, 1.0);
459     if (!theTextAspect.IsZoomable())
460     {
461     #ifdef _WIN32
462       // if the context has assigned printer context, use it's parameters
463       if (!thePrintCtx.IsNull())
464       {
465         // get printing scaling in x and y dimensions
466         GLfloat aTextScalex = 1.0f, aTextScaley = 1.0f;
467         thePrintCtx->GetScale (aTextScalex, aTextScaley);
468
469         // text should be scaled in all directions with same
470         // factor to save its proportions, so use height (y) scaling
471         // as it is better for keeping text/3d graphics proportions
472         glScalef (aTextScaley, aTextScaley, aTextScaley);
473       }
474     #endif
475       glScaled (myScaleHeight, myScaleHeight, myScaleHeight);
476     }
477   }
478 }
479
480 // =======================================================================
481 // function : drawText
482 // purpose  :
483 // =======================================================================
484 void OpenGl_Text::drawText (const Handle(OpenGl_PrinterContext)& thePrintCtx,
485                             const Handle(OpenGl_Context)&        theCtx,
486                             const OpenGl_AspectText&             theTextAspect) const
487 {
488 #ifdef HAVE_GL2PS
489   if (theCtx->IsFeedback())
490   {
491     // position of the text and alignment is calculated by transformation matrix
492     exportText (myString, myIs2d, theTextAspect, (Standard_Integer )myExportHeight);
493     return;
494   }
495 #endif
496
497   if (myVertsVbo.Length() == myTextures.Length())
498   {
499     for (Standard_Integer anIter = 0; anIter < myTextures.Length(); ++anIter)
500     {
501       const GLuint aTexId = myTextures.Value (anIter);
502       const Handle(OpenGl_VertexBuffer)& aVerts = myVertsVbo.Value (anIter);
503       const Handle(OpenGl_VertexBuffer)& aTCrds = myTCrdsVbo.Value (anIter);
504       aVerts->BindFixed (theCtx, GL_VERTEX_ARRAY);
505       aTCrds->BindFixed (theCtx, GL_TEXTURE_COORD_ARRAY);
506       glBindTexture (GL_TEXTURE_2D, aTexId);
507
508       glDrawArrays (GL_TRIANGLES, 0, GLsizei(aVerts->GetElemsNb()));
509
510       glBindTexture (GL_TEXTURE_2D, 0);
511       aTCrds->UnbindFixed (theCtx, GL_TEXTURE_COORD_ARRAY);
512       aVerts->UnbindFixed (theCtx, GL_VERTEX_ARRAY);
513     }
514   }
515   else if (myVertsArray.Length() == myTextures.Length())
516   {
517     glEnableClientState (GL_VERTEX_ARRAY);
518     glEnableClientState (GL_TEXTURE_COORD_ARRAY);
519     for (Standard_Integer anIter = 0; anIter < myTextures.Length(); ++anIter)
520     {
521       const GLuint aTexId = myTextures.Value (anIter);
522       const Handle(OpenGl_Vec2Array)& aVerts = myVertsArray.Value (anIter);
523       const Handle(OpenGl_Vec2Array)& aTCrds = myTCrdsArray.Value (anIter);
524
525       glVertexPointer   (2, GL_FLOAT, 0, (GLfloat* )&aVerts->First());
526       glTexCoordPointer (2, GL_FLOAT, 0, (GLfloat* )&aTCrds->First());
527       glBindTexture (GL_TEXTURE_2D, aTexId);
528
529       glDrawArrays (GL_TRIANGLES, 0, aVerts->Length());
530
531       glBindTexture (GL_TEXTURE_2D, 0);
532     }
533     glDisableClientState (GL_TEXTURE_COORD_ARRAY);
534     glDisableClientState (GL_VERTEX_ARRAY);
535   }
536 }
537
538 // =======================================================================
539 // function : FontKey
540 // purpose  :
541 // =======================================================================
542 TCollection_AsciiString OpenGl_Text::FontKey (const OpenGl_AspectText& theAspect,
543                                               const Standard_Integer   theHeight)
544 {
545   const Font_FontAspect anAspect = (theAspect.FontAspect() != Font_FA_Undefined) ? theAspect.FontAspect() : Font_FA_Regular;
546   return theAspect.FontName()
547        + TCollection_AsciiString(":") + Standard_Integer(anAspect)
548        + TCollection_AsciiString(":") + theHeight;
549 }
550
551 // =======================================================================
552 // function : FindFont
553 // purpose  :
554 // =======================================================================
555 Handle(OpenGl_Font) OpenGl_Text::FindFont (const Handle(OpenGl_Context)& theCtx,
556                                            const OpenGl_AspectText&      theAspect,
557                                            const Standard_Integer        theHeight,
558                                            const TCollection_AsciiString theKey)
559 {
560   Handle(OpenGl_Font) aFont;
561   if (theHeight < 2)
562   {
563     return aFont; // invalid parameters
564   }
565
566   if (!theCtx->GetResource (theKey, aFont))
567   {
568     Handle(Font_FontMgr) aFontMgr = Font_FontMgr::GetInstance();
569     const Handle(TCollection_HAsciiString) aFontName = new TCollection_HAsciiString (theAspect.FontName());
570     const Font_FontAspect anAspect = (theAspect.FontAspect() != Font_FA_Undefined) ? theAspect.FontAspect() : Font_FA_Regular;
571     Handle(Font_SystemFont) aRequestedFont = aFontMgr->FindFont (aFontName, anAspect, theHeight);
572     if (aRequestedFont.IsNull())
573     {
574       return aFont;
575     }
576
577     Handle(Font_FTFont) aFontFt = new Font_FTFont (NULL);
578     if (!aFontFt->Init (aRequestedFont->FontPath()->ToCString(), theHeight))
579     {
580       return aFont;
581     }
582
583     Handle(OpenGl_Context) aCtx = theCtx;
584     glPushAttrib (GL_TEXTURE_BIT);
585     aFont = new OpenGl_Font (aFontFt, theKey);
586     if (!aFont->Init (aCtx))
587     {
588       //glPopAttrib();
589       //return aFont; // out of resources?
590     }
591     glPopAttrib(); // texture bit
592
593     aCtx->ShareResource (theKey, aFont);
594   }
595   return aFont;
596 }
597
598 // =======================================================================
599 // function : render
600 // purpose  :
601 // =======================================================================
602 void OpenGl_Text::render (const Handle(OpenGl_PrinterContext)& thePrintCtx,
603                           const Handle(OpenGl_Context)&        theCtx,
604                           const OpenGl_AspectText&             theTextAspect,
605                           const TEL_COLOUR&                    theColorText,
606                           const TEL_COLOUR&                    theColorSubs) const
607 {
608   if (myString.IsEmpty())
609   {
610     return;
611   }
612
613   const TCollection_AsciiString aFontKey = FontKey (theTextAspect, myParams.Height);
614   if (!myFont.IsNull()
615    && !myFont->ResourceKey().IsEqual (aFontKey))
616   {
617     // font changed
618     const_cast<OpenGl_Text* > (this)->Release (theCtx);
619   }
620
621   if (myFont.IsNull())
622   {
623     myFont = FindFont (theCtx, theTextAspect, myParams.Height, aFontKey);
624     if (myFont.IsNull())
625     {
626       return;
627     }
628   }
629
630   if (myTextures.IsEmpty())
631   {
632     OpenGl_TextFormatter aFormatter;
633     aFormatter.SetupAlignment (myParams.HAlign, myParams.VAlign);
634     aFormatter.Reset();
635     aFormatter.Append (theCtx, myString, *myFont.operator->());
636     aFormatter.Format();
637
638     if (OpenGl_GraphicDriver::ToUseVBO() && theCtx->core15 != NULL)
639     {
640       aFormatter.Result (theCtx, myTextures, myVertsVbo, myTCrdsVbo);
641     }
642     else
643     {
644       aFormatter.Result (theCtx, myTextures, myVertsArray, myTCrdsArray);
645     }
646     aFormatter.BndBox (myBndBox);
647   }
648
649   if (myTextures.IsEmpty())
650   {
651     return;
652   }
653
654   myExportHeight = 1.0f;
655   myScaleHeight  = 1.0f;
656
657   glMatrixMode (GL_MODELVIEW);
658   glPushMatrix();
659   if (!myIs2d)
660   {
661     // retrieve active matrices for project/unproject calls
662     glGetDoublev  (GL_MODELVIEW_MATRIX,  myModelMatrix);
663     glGetDoublev  (GL_PROJECTION_MATRIX, myProjMatrix);
664     glGetIntegerv (GL_VIEWPORT,          myViewport);
665     gluProject (myPoint.x(), myPoint.y(), myPoint.z(),
666                 myModelMatrix, myProjMatrix, myViewport,
667                 &myWinX, &myWinY, &myWinZ);
668
669     // compute scale factor for constant text height
670     GLdouble x1, y1, z1;
671     gluUnProject (myWinX, myWinY, myWinZ,
672                   (GLdouble* )THE_IDENTITY_MATRIX, myProjMatrix, myViewport,
673                   &x1, &y1, &z1);
674
675     GLdouble x2, y2, z2;
676     const GLdouble h = (GLdouble )myFont->FTFont()->PointSize();
677     gluUnProject (myWinX, myWinY + h - 1.0, myWinZ,
678                   (GLdouble* )THE_IDENTITY_MATRIX, myProjMatrix, myViewport,
679                   &x2, &y2, &z2);
680
681     myScaleHeight = (y2 - y1) / h;
682     if (theTextAspect.IsZoomable())
683     {
684       myExportHeight = (float )h;
685     }
686   }
687   myExportHeight = (float )myFont->FTFont()->PointSize() / myExportHeight;
688
689   // push enabled flags to the stack
690   glPushAttrib (GL_ENABLE_BIT);
691
692   // setup depth test
693   if (!myIs2d
694    && theTextAspect.StyleType() != Aspect_TOST_ANNOTATION)
695   {
696     glEnable (GL_DEPTH_TEST);
697   }
698   else
699   {
700     glDisable (GL_DEPTH_TEST);
701   }
702
703   // setup alpha test
704   GLint aTexEnvParam = GL_REPLACE;
705   glGetTexEnviv (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, &aTexEnvParam);
706   if (aTexEnvParam != GL_REPLACE)
707   {
708     glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
709   }
710   glAlphaFunc (GL_GEQUAL, 0.285f);
711   glEnable (GL_ALPHA_TEST);
712
713   // setup blending
714   glEnable (GL_BLEND);
715   glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // GL_ONE
716
717   // activate texture unit
718   glDisable (GL_TEXTURE_1D);
719   glEnable  (GL_TEXTURE_2D);
720   if (theCtx->core13 != NULL)
721   {
722     theCtx->core13->glActiveTexture (GL_TEXTURE0);
723   }
724
725   // extra drawings
726   switch (theTextAspect.DisplayType())
727   {
728     case Aspect_TODT_BLEND:
729     {
730       glEnable  (GL_COLOR_LOGIC_OP);
731       glLogicOp (GL_XOR);
732       break;
733     }
734     case Aspect_TODT_SUBTITLE:
735     {
736       glColor3fv  (theColorSubs.rgb);
737       setupMatrix (thePrintCtx, theCtx, theTextAspect, OpenGl_Vec3 (0.0f, 0.0f, 0.00001f));
738
739       glBindTexture (GL_TEXTURE_2D, 0);
740       glBegin (GL_QUADS);
741       glVertex2f (myBndBox.Left,  myBndBox.Top);
742       glVertex2f (myBndBox.Right, myBndBox.Top);
743       glVertex2f (myBndBox.Right, myBndBox.Bottom);
744       glVertex2f (myBndBox.Left,  myBndBox.Bottom);
745       glEnd();
746       break;
747     }
748     case Aspect_TODT_DEKALE:
749     {
750       glColor3fv  (theColorSubs.rgb);
751       setupMatrix (thePrintCtx, theCtx, theTextAspect, OpenGl_Vec3 (+1.0f, +1.0f, 0.00001f));
752       drawText    (thePrintCtx, theCtx, theTextAspect);
753       setupMatrix (thePrintCtx, theCtx, theTextAspect, OpenGl_Vec3 (-1.0f, -1.0f, 0.00001f));
754       drawText    (thePrintCtx, theCtx, theTextAspect);
755       setupMatrix (thePrintCtx, theCtx, theTextAspect, OpenGl_Vec3 (-1.0f, +1.0f, 0.00001f));
756       drawText    (thePrintCtx, theCtx, theTextAspect);
757       setupMatrix (thePrintCtx, theCtx, theTextAspect, OpenGl_Vec3 (+1.0f, -1.0f, 0.00001f));
758       drawText    (thePrintCtx, theCtx, theTextAspect);
759       break;
760     }
761     case Aspect_TODT_NORMAL:
762     {
763       break;
764     }
765   }
766
767   // main draw call
768   glColor3fv  (theColorText.rgb);
769   setupMatrix (thePrintCtx, theCtx, theTextAspect, OpenGl_Vec3 (0.0f, 0.0f, 0.0f));
770   drawText    (thePrintCtx, theCtx, theTextAspect);
771
772   // revert OpenGL state
773   glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, aTexEnvParam);
774   glPopAttrib(); // enable bit
775   glPopMatrix(); // model view matrix was modified
776 }