0025219: Visualization, TKOpenGl - disable code paths unavailable on OpenGL ES 2.0
[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 // This file is part of Open CASCADE Technology software library.
6 //
7 // This library is free software; you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License version 2.1 as published
9 // by the Free Software Foundation, with special exception defined in the file
10 // OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
11 // distribution for complete text of the license and disclaimer of any warranty.
12 //
13 // Alternatively, this file may be used under the terms of Open CASCADE
14 // commercial license or contractual agreement.
15
16 #include <OpenGl_AspectText.hxx>
17 #include <OpenGl_GlCore11.hxx>
18 #include <OpenGl_GraphicDriver.hxx>
19 #include <OpenGl_ShaderManager.hxx>
20 #include <OpenGl_ShaderProgram.hxx>
21 #include <OpenGl_ShaderStates.hxx>
22 #include <OpenGl_Text.hxx>
23 #include <OpenGl_Workspace.hxx>
24
25 #include <Font_FontMgr.hxx>
26 #include <TCollection_HAsciiString.hxx>
27
28 #ifdef HAVE_GL2PS
29   #include <gl2ps.h>
30 #endif
31
32 namespace
33 {
34   static const GLdouble THE_IDENTITY_MATRIX[4][4] =
35   {
36     {1.,0.,0.,0.},
37     {0.,1.,0.,0.},
38     {0.,0.,1.,0.},
39     {0.,0.,0.,1.}
40   };
41
42 #ifdef HAVE_GL2PS
43   static char const* TheFamily[] = {"Helvetica", "Courier", "Times"};
44   static char const* TheItalic[] = {"Oblique",   "Oblique", "Italic"};
45   static char const* TheBase[]   = {"", "", "-Roman"};
46
47   //! Convert font name used for rendering to some "good" font names
48   //! that produce good vector text.
49   static void getGL2PSFontName (const char* theSrcFont,
50                                 char*       thePsFont)
51   {
52     if (strstr (theSrcFont, "Symbol"))
53     {
54       sprintf (thePsFont, "%s", "Symbol");
55       return;
56     }
57     else if (strstr (theSrcFont, "ZapfDingbats"))
58     {
59       sprintf (thePsFont, "%s", "WingDings");
60       return;
61     }
62
63     int  aFontId  = 0;
64     bool isBold   = false;
65     bool isItalic = false;
66     if (strstr (theSrcFont, "Courier"))
67     {
68       aFontId = 1;
69     }
70     else if (strstr (theSrcFont, "Times"))
71     {
72       aFontId = 2;
73     }
74
75     if (strstr (theSrcFont, "Bold"))
76     {
77       isBold = true;
78     }
79     if (strstr (theSrcFont, "Italic")
80      || strstr (theSrcFont, "Oblique"))
81     {
82       isItalic = true;
83     }
84
85     if (isBold)
86     {
87       if (isItalic)
88       {
89         sprintf (thePsFont, "%s-Bold%s", TheFamily[aFontId], TheItalic[aFontId]);
90       }
91       else
92       {
93         sprintf (thePsFont, "%s-Bold", TheFamily[aFontId]);
94       }
95     }
96     else if (isItalic)
97     {
98       sprintf (thePsFont, "%s-%s", TheFamily[aFontId], TheItalic[aFontId]);
99     }
100     else
101     {
102       sprintf (thePsFont, "%s%s", TheFamily[aFontId], TheBase[aFontId]);
103     }
104   }
105
106   static void exportText (const NCollection_String& theText,
107                           const Standard_Boolean    theIs2d,
108                           const OpenGl_AspectText&  theAspect,
109                           const Standard_Integer    theHeight)
110   {
111
112     char aPsFont[64];
113     getGL2PSFontName (theAspect.FontName().ToCString(), aPsFont);
114
115   #if !defined(GL_ES_VERSION_2_0)
116     if (theIs2d)
117     {
118       glRasterPos2f (0.0f, 0.0f);
119     }
120     else
121     {
122       glRasterPos3f (0.0f, 0.0f, 0.0f);
123     }
124
125     GLubyte aZero = 0;
126     glBitmap (1, 1, 0, 0, 0, 0, &aZero);
127   #endif
128
129     // Standard GL2PS's alignment isn't used, because it doesn't work correctly
130     // for all formats, therefore alignment is calculated manually relative
131     // to the bottom-left corner, which corresponds to the GL2PS_TEXT_BL value
132     gl2psTextOpt (theText.ToCString(), aPsFont, (GLshort)theHeight, GL2PS_TEXT_BL, theAspect.Angle());
133   }
134 #endif
135
136 };
137
138 // =======================================================================
139 // function : OpenGl_Text
140 // purpose  :
141 // =======================================================================
142 OpenGl_Text::OpenGl_Text()
143 : myWinX (0.0f),
144   myWinY (0.0f),
145   myWinZ (0.0f),
146   myScaleHeight (1.0f),
147   myPoint  (0.0f, 0.0f, 0.0f),
148   myIs2d   (false)
149 {
150   myParams.Height = 10;
151   myParams.HAlign = Graphic3d_HTA_LEFT;
152   myParams.VAlign = Graphic3d_VTA_BOTTOM;
153 }
154
155 // =======================================================================
156 // function : OpenGl_Text
157 // purpose  :
158 // =======================================================================
159 OpenGl_Text::OpenGl_Text (const Standard_Utf8Char* theText,
160                           const OpenGl_Vec3&       thePoint,
161                           const OpenGl_TextParam&  theParams)
162 : myWinX (0.0f),
163   myWinY (0.0f),
164   myWinZ (0.0f),
165   myScaleHeight  (1.0f),
166   myExportHeight (1.0f),
167   myParams (theParams),
168   myString (theText),
169   myPoint  (thePoint),
170   myIs2d   (false)
171 {
172   //
173 }
174
175 // =======================================================================
176 // function : SetPosition
177 // purpose  :
178 // =======================================================================
179 void OpenGl_Text::SetPosition (const OpenGl_Vec3& thePoint)
180 {
181   myPoint = thePoint;
182 }
183
184 // =======================================================================
185 // function : SetFontSize
186 // purpose  :
187 // =======================================================================
188 void OpenGl_Text::SetFontSize (const Handle(OpenGl_Context)& theCtx,
189                                const Standard_Integer        theFontSize)
190 {
191   if (myParams.Height != theFontSize)
192   {
193     Release (theCtx.operator->());
194   }
195   myParams.Height = theFontSize;
196 }
197
198 // =======================================================================
199 // function : Init
200 // purpose  :
201 // =======================================================================
202 void OpenGl_Text::Init (const Handle(OpenGl_Context)& theCtx,
203                         const Standard_Utf8Char*      theText,
204                         const OpenGl_Vec3&            thePoint)
205 {
206   releaseVbos (theCtx.operator->());
207   myIs2d   = false;
208   myPoint  = thePoint;
209   myString.FromUnicode (theText);
210 }
211
212 // =======================================================================
213 // function : Init
214 // purpose  :
215 // =======================================================================
216 void OpenGl_Text::Init (const Handle(OpenGl_Context)& theCtx,
217                         const Standard_Utf8Char*      theText,
218                         const OpenGl_Vec3&            thePoint,
219                         const OpenGl_TextParam&       theParams)
220 {
221   if (myParams.Height != theParams.Height)
222   {
223     Release (theCtx.operator->());
224   }
225   else
226   {
227     releaseVbos (theCtx.operator->());
228   }
229   myIs2d   = false;
230   myParams = theParams;
231   myPoint  = thePoint;
232   myString.FromUnicode (theText);
233 }
234
235 // =======================================================================
236 // function : Init
237 // purpose  :
238 // =======================================================================
239 void OpenGl_Text::Init (const Handle(OpenGl_Context)&     theCtx,
240                         const TCollection_ExtendedString& theText,
241                         const OpenGl_Vec2&                thePoint,
242                         const OpenGl_TextParam&           theParams)
243 {
244   if (myParams.Height != theParams.Height)
245   {
246     Release (theCtx.operator->());
247   }
248   else
249   {
250     releaseVbos (theCtx.operator->());
251   }
252   myIs2d       = true;
253   myParams     = theParams;
254   myPoint.xy() = thePoint;
255   myPoint.z()  = 0.0f;
256   myString.FromUnicode ((Standard_Utf16Char* )theText.ToExtString());
257 }
258
259 // =======================================================================
260 // function : ~OpenGl_Text
261 // purpose  :
262 // =======================================================================
263 OpenGl_Text::~OpenGl_Text()
264 {
265   //
266 }
267
268 // =======================================================================
269 // function : releaseVbos
270 // purpose  :
271 // =======================================================================
272 void OpenGl_Text::releaseVbos (OpenGl_Context* theCtx)
273 {
274   for (Standard_Integer anIter = 0; anIter < myVertsVbo.Length(); ++anIter)
275   {
276     Handle(OpenGl_VertexBuffer)& aVerts = myVertsVbo.ChangeValue (anIter);
277     Handle(OpenGl_VertexBuffer)& aTCrds = myTCrdsVbo.ChangeValue (anIter);
278
279     if (theCtx)
280     {
281       theCtx->DelayedRelease (aVerts);
282       theCtx->DelayedRelease (aTCrds);
283     }
284     aVerts.Nullify();
285     aTCrds.Nullify();
286   }
287   myTextures.Clear();
288   myVertsVbo.Clear();
289   myTCrdsVbo.Clear();
290 }
291
292 // =======================================================================
293 // function : Release
294 // purpose  :
295 // =======================================================================
296 void OpenGl_Text::Release (OpenGl_Context* theCtx)
297 {
298   releaseVbos (theCtx);
299   if (!myFont.IsNull())
300   {
301     Handle(OpenGl_Context) aCtx = theCtx;
302     const TCollection_AsciiString aKey = myFont->ResourceKey();
303     myFont.Nullify();
304     if (aCtx)
305       aCtx->ReleaseResource (aKey, Standard_True);
306   }
307 }
308
309 // =======================================================================
310 // function : StringSize
311 // purpose  :
312 // =======================================================================
313 void OpenGl_Text::StringSize (const Handle(OpenGl_Context)& theCtx,
314                               const NCollection_String&     theText,
315                               const OpenGl_AspectText&      theTextAspect,
316                               const OpenGl_TextParam&       theParams,
317                               Standard_ShortReal&           theWidth,
318                               Standard_ShortReal&           theAscent,
319                               Standard_ShortReal&           theDescent)
320 {
321   theWidth   = 0.0f;
322   theAscent  = 0.0f;
323   theDescent = 0.0f;
324   const TCollection_AsciiString aFontKey = FontKey (theTextAspect, theParams.Height);
325   Handle(OpenGl_Font) aFont = FindFont (theCtx, theTextAspect, theParams.Height, aFontKey);
326   if (aFont.IsNull() || !aFont->IsValid())
327   {
328     return;
329   }
330
331   theAscent  = aFont->Ascender();
332   theDescent = aFont->Descender();
333
334   GLfloat aWidth = 0.0f;
335   for (NCollection_Utf8Iter anIter = theText.Iterator(); *anIter != 0;)
336   {
337     const Standard_Utf32Char aCharThis =   *anIter;
338     const Standard_Utf32Char aCharNext = *++anIter;
339
340     if (aCharThis == '\x0D' // CR  (carriage return)
341      || aCharThis == '\a'   // BEL (alarm)
342      || aCharThis == '\f'   // FF  (form feed) NP (new page)
343      || aCharThis == '\b'   // BS  (backspace)
344      || aCharThis == '\v')  // VT  (vertical tab)
345     {
346       continue; // skip unsupported carriage control codes
347     }
348     else if (aCharThis == '\x0A') // LF (line feed, new line)
349     {
350       theWidth = Max (theWidth, aWidth);
351       aWidth   = 0.0f;
352       continue;
353     }
354     else if (aCharThis == ' ')
355     {
356       aWidth += aFont->AdvanceX (aCharThis, aCharNext);
357       continue;
358     }
359     else if (aCharThis == '\t')
360     {
361       aWidth += aFont->AdvanceX (' ', aCharNext) * 8.0f;
362       continue;
363     }
364
365     aWidth += aFont->AdvanceX (aCharThis, aCharNext);
366   }
367   theWidth = Max (theWidth, aWidth);
368
369   Handle(OpenGl_Context) aCtx = theCtx;
370   aFont.Nullify();
371   aCtx->ReleaseResource (aFontKey, Standard_True);
372 }
373
374 // =======================================================================
375 // function : Render
376 // purpose  :
377 // =======================================================================
378 void OpenGl_Text::Render (const Handle(OpenGl_Workspace)& theWorkspace) const
379 {
380   const OpenGl_AspectText* aTextAspect = theWorkspace->AspectText (Standard_True);
381   const Handle(OpenGl_Texture) aPrevTexture = theWorkspace->DisableTexture();
382
383   const Handle(OpenGl_Context)& aCtx = theWorkspace->GetGlContext();
384
385   if (aCtx->IsGlGreaterEqual (2, 0))
386   {
387     const Handle(OpenGl_ShaderProgram)& aProgram = aTextAspect->ShaderProgramRes (theWorkspace);
388     aCtx->BindProgram (aProgram);
389     if (!aProgram.IsNull())
390     {
391       aProgram->ApplyVariables (aCtx);
392
393       const OpenGl_MaterialState* aMaterialState = aCtx->ShaderManager()->MaterialState (aProgram);
394
395       if (aMaterialState == NULL || aMaterialState->Aspect() != aTextAspect)
396         aCtx->ShaderManager()->UpdateMaterialStateTo (aProgram, aTextAspect);
397
398       aCtx->ShaderManager()->PushState (aProgram);
399     }
400   }
401
402   // use highlight color or colors from aspect
403   if (theWorkspace->NamedStatus & OPENGL_NS_HIGHLIGHT)
404   {
405     render (theWorkspace->PrinterContext(),
406             aCtx,
407             *aTextAspect,
408             *theWorkspace->HighlightColor,
409             *theWorkspace->HighlightColor);
410   }
411   else
412   {
413     render (theWorkspace->PrinterContext(),
414             aCtx,
415             *aTextAspect,
416             aTextAspect->Color(),
417             aTextAspect->SubtitleColor());
418   }
419
420   // restore aspects
421   if (!aPrevTexture.IsNull())
422   {
423     theWorkspace->EnableTexture (aPrevTexture);
424   }
425 }
426
427 // =======================================================================
428 // function : Render
429 // purpose  :
430 // =======================================================================
431 void OpenGl_Text::Render (const Handle(OpenGl_PrinterContext)& thePrintCtx,
432                           const Handle(OpenGl_Context)&        theCtx,
433                           const OpenGl_AspectText&             theTextAspect) const
434 {
435   render (thePrintCtx, theCtx, theTextAspect, theTextAspect.Color(), theTextAspect.SubtitleColor());
436 }
437
438 // =======================================================================
439 // function : setupMatrix
440 // purpose  :
441 // =======================================================================
442 void OpenGl_Text::setupMatrix (const Handle(OpenGl_PrinterContext)& thePrintCtx,
443                                const Handle(OpenGl_Context)&        theCtx,
444                                const OpenGl_AspectText&             theTextAspect,
445                                const OpenGl_Vec3                    theDVec) const
446 {
447   // setup matrix
448 #if !defined(GL_ES_VERSION_2_0)
449   if (myIs2d)
450   {
451     glLoadIdentity();
452     glTranslatef (myPoint.x() + theDVec.x(), myPoint.y() + theDVec.y(), 0.0f);
453     glScalef (1.0f, -1.0f, 1.0f);
454     glRotatef (theTextAspect.Angle(), 0.0, 0.0, 1.0);
455   }
456   else
457   {
458     // align coordinates to the nearest integer
459     // to avoid extra interpolation issues
460     GLdouble anObjX, anObjY, anObjZ;
461     gluUnProject (std::floor (myWinX + (GLdouble )theDVec.x()),
462                   std::floor (myWinY + (GLdouble )theDVec.y()),
463                   myWinZ + (GLdouble )theDVec.z(),
464                   (GLdouble* )THE_IDENTITY_MATRIX, myProjMatrix, myViewport,
465                   &anObjX, &anObjY, &anObjZ);
466
467     glLoadIdentity();
468     theCtx->core11->glTranslated (anObjX, anObjY, anObjZ);
469     theCtx->core11->glRotated (theTextAspect.Angle(), 0.0, 0.0, 1.0);
470     if (!theTextAspect.IsZoomable())
471     {
472     #ifdef _WIN32
473       // if the context has assigned printer context, use it's parameters
474       if (!thePrintCtx.IsNull())
475       {
476         // get printing scaling in x and y dimensions
477         GLfloat aTextScalex = 1.0f, aTextScaley = 1.0f;
478         thePrintCtx->GetScale (aTextScalex, aTextScaley);
479
480         // text should be scaled in all directions with same
481         // factor to save its proportions, so use height (y) scaling
482         // as it is better for keeping text/3d graphics proportions
483         theCtx->core11->glScaled ((GLfloat )aTextScaley, (GLfloat )aTextScaley, (GLfloat )aTextScaley);
484       }
485     #endif
486       theCtx->core11->glScaled (myScaleHeight, myScaleHeight, myScaleHeight);
487     }
488   }
489 #endif
490 }
491
492 // =======================================================================
493 // function : drawText
494 // purpose  :
495 // =======================================================================
496
497 void OpenGl_Text::drawText (const Handle(OpenGl_PrinterContext)& ,
498                             const Handle(OpenGl_Context)&        theCtx,
499                           #ifdef HAVE_GL2PS
500                             const OpenGl_AspectText&             theTextAspect) const
501                           #else
502                             const OpenGl_AspectText&                          ) const
503                           #endif
504 {
505 #ifdef HAVE_GL2PS
506   if (theCtx->IsFeedback())
507   {
508     // position of the text and alignment is calculated by transformation matrix
509     exportText (myString, myIs2d, theTextAspect, (Standard_Integer )myExportHeight);
510     return;
511   }
512 #endif
513
514   if (myVertsVbo.Length() != myTextures.Length()
515    || myTextures.IsEmpty())
516   {
517     return;
518   }
519
520   for (Standard_Integer anIter = 0; anIter < myTextures.Length(); ++anIter)
521   {
522     const GLuint aTexId = myTextures.Value (anIter);
523     glBindTexture (GL_TEXTURE_2D, aTexId);
524
525     const Handle(OpenGl_VertexBuffer)& aVerts = myVertsVbo.Value (anIter);
526     const Handle(OpenGl_VertexBuffer)& aTCrds = myTCrdsVbo.Value (anIter);
527     aVerts->BindAttribute (theCtx, Graphic3d_TOA_POS);
528     aTCrds->BindAttribute (theCtx, Graphic3d_TOA_UV);
529
530     glDrawArrays (GL_TRIANGLES, 0, GLsizei(aVerts->GetElemsNb()));
531
532     aVerts->UnbindAttribute (theCtx, Graphic3d_TOA_UV);
533     aVerts->UnbindAttribute (theCtx, Graphic3d_TOA_POS);
534   }
535   glBindTexture (GL_TEXTURE_2D, 0);
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   #if !defined(GL_ES_VERSION_2_0)
585     glPushAttrib (GL_TEXTURE_BIT);
586   #endif
587     aFont = new OpenGl_Font (aFontFt, theKey);
588     if (!aFont->Init (aCtx))
589     {
590       //glPopAttrib();
591       //return aFont; // out of resources?
592     }
593   #if !defined(GL_ES_VERSION_2_0)
594     glPopAttrib(); // texture bit
595   #endif
596
597     aCtx->ShareResource (theKey, aFont);
598   }
599   return aFont;
600 }
601
602 // =======================================================================
603 // function : render
604 // purpose  :
605 // =======================================================================
606 void OpenGl_Text::render (const Handle(OpenGl_PrinterContext)& thePrintCtx,
607                           const Handle(OpenGl_Context)&        theCtx,
608                           const OpenGl_AspectText&             theTextAspect,
609                           const TEL_COLOUR&                    theColorText,
610                           const TEL_COLOUR&                    theColorSubs) const
611 {
612   if (myString.IsEmpty())
613   {
614     return;
615   }
616
617   const TCollection_AsciiString aFontKey = FontKey (theTextAspect, myParams.Height);
618   if (!myFont.IsNull()
619    && !myFont->ResourceKey().IsEqual (aFontKey))
620   {
621     // font changed
622     const_cast<OpenGl_Text* > (this)->Release (theCtx.operator->());
623   }
624
625   if (myFont.IsNull())
626   {
627     myFont = FindFont (theCtx, theTextAspect, myParams.Height, aFontKey);
628     if (myFont.IsNull())
629     {
630       return;
631     }
632   }
633
634   if (myTextures.IsEmpty())
635   {
636     OpenGl_TextFormatter aFormatter;
637     aFormatter.SetupAlignment (myParams.HAlign, myParams.VAlign);
638     aFormatter.Reset();
639     aFormatter.Append (theCtx, myString, *myFont.operator->());
640     aFormatter.Format();
641
642     aFormatter.Result (theCtx, myTextures, myVertsVbo, myTCrdsVbo);
643     aFormatter.BndBox (myBndBox);
644   }
645
646   if (myTextures.IsEmpty())
647   {
648     return;
649   }
650
651   myExportHeight = 1.0f;
652   myScaleHeight  = 1.0f;
653
654 #if !defined(GL_ES_VERSION_2_0)
655   glMatrixMode (GL_MODELVIEW);
656   glPushMatrix();
657   if (!myIs2d)
658   {
659     // retrieve active matrices for project/unproject calls
660     glGetDoublev  (GL_MODELVIEW_MATRIX,  myModelMatrix);
661     glGetDoublev  (GL_PROJECTION_MATRIX, myProjMatrix);
662     glGetIntegerv (GL_VIEWPORT,          myViewport);
663     gluProject (myPoint.x(), myPoint.y(), myPoint.z(),
664                 myModelMatrix, myProjMatrix, myViewport,
665                 &myWinX, &myWinY, &myWinZ);
666
667     // compute scale factor for constant text height
668     GLdouble x1, y1, z1;
669     gluUnProject (myWinX, myWinY, myWinZ,
670                   (GLdouble* )THE_IDENTITY_MATRIX, myProjMatrix, myViewport,
671                   &x1, &y1, &z1);
672
673     GLdouble x2, y2, z2;
674     const GLdouble h = (GLdouble )myFont->FTFont()->PointSize();
675     gluUnProject (myWinX, myWinY + h, myWinZ,
676                   (GLdouble* )THE_IDENTITY_MATRIX, myProjMatrix, myViewport,
677                   &x2, &y2, &z2);
678
679     myScaleHeight = (y2 - y1) / h;
680     if (theTextAspect.IsZoomable())
681     {
682       myExportHeight = (float )h;
683     }
684   }
685   myExportHeight = (float )myFont->FTFont()->PointSize() / myExportHeight;
686
687   // push enabled flags to the stack
688   glPushAttrib (GL_ENABLE_BIT);
689   glDisable (GL_LIGHTING);
690
691   // setup depth test
692   if (!myIs2d
693    && theTextAspect.StyleType() != Aspect_TOST_ANNOTATION)
694   {
695     glEnable (GL_DEPTH_TEST);
696   }
697   else
698   {
699     glDisable (GL_DEPTH_TEST);
700   }
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->core15fwd != NULL)
721   {
722     theCtx->core15fwd->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       theCtx->core11->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       theCtx->core11->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_DIMENSION:
762     case Aspect_TODT_NORMAL:
763     {
764       break;
765     }
766   }
767
768   // main draw call
769   theCtx->core11->glColor3fv (theColorText.rgb);
770   setupMatrix (thePrintCtx, theCtx, theTextAspect, OpenGl_Vec3 (0.0f, 0.0f, 0.0f));
771   drawText    (thePrintCtx, theCtx, theTextAspect);
772
773   glTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, aTexEnvParam);
774
775   if (theTextAspect.DisplayType() == Aspect_TODT_DIMENSION)
776   {
777     setupMatrix (thePrintCtx, theCtx, theTextAspect, OpenGl_Vec3 (0.0f, 0.0f, 0.00001f));
778
779     glDisable (GL_BLEND);
780     glDisable (GL_TEXTURE_2D);
781     glDisable (GL_ALPHA_TEST);
782     if (!myIs2d)
783     {
784       glDisable (GL_DEPTH_TEST);
785     }
786     glColorMask (GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
787
788     glClear (GL_STENCIL_BUFFER_BIT);
789     glEnable (GL_STENCIL_TEST);
790     glStencilFunc (GL_ALWAYS, 1, 0xFF);
791     glStencilOp (GL_KEEP, GL_KEEP, GL_REPLACE);
792
793     glBegin (GL_QUADS);
794     glVertex2f (myBndBox.Left,  myBndBox.Top);
795     glVertex2f (myBndBox.Right, myBndBox.Top);
796     glVertex2f (myBndBox.Right, myBndBox.Bottom);
797     glVertex2f (myBndBox.Left,  myBndBox.Bottom);
798     glEnd();
799
800     glStencilFunc (GL_ALWAYS, 0, 0xFF);
801     // glPopAttrib() will reset state for us
802     //glDisable (GL_STENCIL_TEST);
803     //if (!myIs2d) glEnable (GL_DEPTH_TEST);
804
805     glColorMask (GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
806   }
807
808   // revert OpenGL state
809   glPopAttrib(); // enable bit
810   glPopMatrix(); // model view matrix was modified
811 #endif
812 }